gui-tests-framework: ScriptRecorder moved to community-tests

This commit is contained in:
Sergey Karashevich
2016-10-09 17:59:25 +03:00
parent 45914c9cd1
commit 17f607abcb
12 changed files with 299 additions and 38 deletions
+19 -24
View File
@@ -3,24 +3,15 @@
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/testsSrc" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="jdk" jdkName="1.8" jdkType="JavaSDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module-library" scope="TEST">
<library name="JUnit4">
<CLASSES>
<root url="jar://$APPLICATION_HOME_DIR$/lib/junit-4.12.jar!/" />
<root url="jar://$APPLICATION_HOME_DIR$/lib/hamcrest-core-1.3.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module" module-name="core-api" scope="TEST" />
<orderEntry type="module" module-name="core-api" />
<orderEntry type="library" name="fest" level="project" />
<orderEntry type="module" module-name="platform-impl" scope="TEST" />
<orderEntry type="module" module-name="testFramework" scope="TEST" />
<orderEntry type="module" module-name="platform-impl" />
<orderEntry type="module" module-name="testFramework" />
<orderEntry type="module-library">
<library>
<CLASSES>
@@ -30,14 +21,14 @@
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module" module-name="java-psi-api" scope="TEST" />
<orderEntry type="module" module-name="bootstrap" scope="TEST" />
<orderEntry type="module" module-name="external-system-rt" scope="TEST" />
<orderEntry type="module" module-name="xdebugger-impl" scope="TEST" />
<orderEntry type="module" module-name="external-system-impl" scope="TEST" />
<orderEntry type="module" module-name="openapi" scope="TEST" />
<orderEntry type="module" module-name="lint-api" scope="TEST" />
<orderEntry type="module" module-name="testRunner" scope="TEST" />
<orderEntry type="module" module-name="java-psi-api" />
<orderEntry type="module" module-name="bootstrap" />
<orderEntry type="module" module-name="external-system-rt" />
<orderEntry type="module" module-name="xdebugger-impl" />
<orderEntry type="module" module-name="external-system-impl" />
<orderEntry type="module" module-name="openapi" />
<orderEntry type="module" module-name="lint-api" />
<orderEntry type="module" module-name="testRunner" />
<orderEntry type="module-library">
<library>
<CLASSES>
@@ -49,7 +40,11 @@
</SOURCES>
</library>
</orderEntry>
<orderEntry type="module" module-name="idea-ui" scope="TEST" />
<orderEntry type="module" module-name="dvcs-impl" scope="TEST" />
<orderEntry type="module" module-name="idea-ui" />
<orderEntry type="module" module-name="dvcs-impl" />
<orderEntry type="module" module-name="annotations" />
<orderEntry type="module" module-name="main_idea_tests" />
<orderEntry type="module" module-name="lang-impl" />
<orderEntry type="library" name="JUnit4" level="project" />
</component>
</module>
@@ -0,0 +1,6 @@
<idea-plugin>
<extensions defaultExtensionNs="com.intellij">
<uiDropperActions implementation="com.intellij.tests.gui.script.ScriptRecorder"/>
</extensions>
</idea-plugin>
@@ -21,6 +21,7 @@ import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectBundle;
import com.intellij.openapi.project.ProjectUtil;
import com.intellij.tests.gui.fixtures.ActionLinkFixture;
import com.intellij.tests.gui.fixtures.ProjectViewFixture;
import com.intellij.tests.gui.fixtures.ToolWindowFixture;
import com.intellij.tests.gui.fixtures.newProjectWizard.NewProjectWizardFixture;
@@ -15,15 +15,16 @@
*/
package com.intellij.tests.gui
import com.intellij.tests.gui.fixtures.ActionLinkFixture
import com.intellij.tests.gui.fixtures.DialogFixtures.CreateDialogFixture
import com.intellij.tests.gui.fixtures.EditorFixture
import com.intellij.tests.gui.fixtures.JBPopupFixture
import com.intellij.tests.gui.framework.GuiTestCase
import com.intellij.tests.gui.framework.TestGroup
import com.intellij.tests.gui.framework.createNewProject
import com.intellij.tests.gui.framework.*
import com.intellij.ui.components.JBList
import org.junit.Ignore
import org.junit.Test
import java.io.File
import javax.swing.JTextField
import javax.swing.text.JTextComponent
/**
@@ -42,7 +43,8 @@ class JavaProjectTest: GuiTestCase() {
val newProjectWizard = findNewProjectWizard()
with(newProjectWizard){
setupJdk()
selectProjectType("Java")
// selectProjectType("Java")
clickListItem("Java", robot(), this.target())
selectFramework("JavaEE Persistence")
clickNext()
setProjectName(projectName);
@@ -33,6 +33,7 @@ import static com.intellij.util.containers.ContainerUtil.getFirstItem;
import static org.fest.swing.timing.Pause.pause;
public class ActionLinkFixture extends JComponentFixture<ActionLinkFixture, ActionLink> {
@NotNull
public static ActionLinkFixture findByActionId(@NotNull final String actionId,
@NotNull final Robot robot,
@@ -67,6 +68,39 @@ public class ActionLinkFixture extends JComponentFixture<ActionLinkFixture, Acti
return new ActionLinkFixture(robot, actionLink);
}
@NotNull
public static ActionLinkFixture findActionLinkByName(@NotNull final String actionName,
@NotNull final Robot robot,
@NotNull final Container container) {
final Ref<ActionLink> actionLinkRef = new Ref<ActionLink>();
pause(new Condition("Find ActionLink with name '" + actionName + "'") {
@Override
public boolean test() {
Collection<ActionLink> found = robot.finder().findAll(container, new GenericTypeMatcher<ActionLink>(ActionLink.class) {
@Override
protected boolean isMatching(@NotNull ActionLink actionLink) {
if (actionLink.isVisible()) {
return actionLink.getText().equals(actionName);
}
return false;
}
});
if (found.size() == 1) {
actionLinkRef.set(getFirstItem(found));
return true;
}
return false;
}
}, SHORT_TIMEOUT);
ActionLink actionLink = actionLinkRef.get();
if (actionLink == null) {
throw new ComponentLookupException("Failed to find ActionLink with name '" + actionName + "'");
}
return new ActionLinkFixture(robot, actionLink);
}
private ActionLinkFixture(@NotNull Robot robot, @NotNull ActionLink target) {
super(ActionLinkFixture.class, robot, target);
}
@@ -41,9 +41,7 @@ import com.intellij.ui.popup.PopupFactoryImpl;
import com.intellij.ui.popup.list.ListPopupModel;
import com.intellij.util.JdkBundle;
import com.intellij.util.ui.EdtInvocationManager;
import org.fest.swing.core.BasicRobot;
import org.fest.swing.core.ComponentFinder;
import org.fest.swing.core.GenericTypeMatcher;
import org.fest.swing.core.*;
import org.fest.swing.core.Robot;
import org.fest.swing.edt.GuiActionRunner;
import org.fest.swing.edt.GuiQuery;
@@ -609,6 +607,18 @@ public final class GuiTests {
}
}
@Nullable
public static JLabel findBoundedLabel(@NotNull Container container, @NotNull JTextField textField, @NotNull Robot robot) {
Collection<JLabel> labels = robot.finder().findAll(container, new GenericTypeMatcher<JLabel>(JLabel.class) {
@Override
protected boolean isMatching(@Nonnull JLabel label) {
return label.getLabelFor().equals(textField);
}
});
if (labels != null && !labels.isEmpty()) return labels.iterator().next();
else return null;
}
@NotNull
public static JButton findButton(@NotNull ContainerFixture<? extends Container> container, @NotNull final String text, Robot robot) {
return robot.finder().find(container.target(), new GenericTypeMatcher<JButton>(JButton.class) {
@@ -741,4 +751,6 @@ public final class GuiTests {
String homeSubPath = SystemInfo.isMac ? "/Contents/Home" : "";
return jdkBundle.getLocation().getAbsolutePath() + homeSubPath;
}
}
@@ -2,9 +2,12 @@ package com.intellij.tests.gui.framework
import com.intellij.openapi.ui.JBPopupMenu
import com.intellij.tests.gui.fixtures.WelcomeFrameFixture
import com.intellij.ui.components.JBList
import org.fest.swing.core.Robot
import org.fest.swing.fixture.JListFixture
import org.fest.swing.timing.Condition
import org.fest.swing.timing.Pause
import java.awt.Container
/**
We presume that IDEA is already started, shows "Welcome dialog" and we could create a new project
@@ -22,4 +25,9 @@ fun pause(time: Long, root: Robot) {
}
}, time)
}
fun clickListItem(itemName: String, robot: Robot, parentContainer: Container) {
val listFixture = JListFixture(robot, robot.finder().findByType(parentContainer, JBList::class.java, true))
listFixture.clickItem(itemName)
}
@@ -0,0 +1,157 @@
/*
* Copyright 2000-2016 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.tests.gui.script
import com.intellij.internal.inspector.UiDropperActionExtension
import com.intellij.openapi.actionSystem.AnAction
import java.awt.Component
import javax.swing.*
/**
* Created by jetbrains on 18/08/16.
*/
/**
* ScriptRecorder needs to create GUI Tests quickly. For recording UI actions like click, text entering, checkbox marking we using UI dropper.
*/
class ScriptRecorder() : AnAction(), UiDropperActionExtension {
override fun getAnAction(): com.intellij.openapi.actionSystem.AnAction? {
return this
}
var currentContextComponent: Component? = null
private var currentContext = Contexts()
override fun actionPerformed(e: com.intellij.openapi.actionSystem.AnActionEvent?) {
//get action type for script: click, enter text, mark checkbox
val component = e!!.getDataContext().getData("Component") as Component
checkContext(component)
clickCmp(component, e)
}
//registering custom actions for a UI Dropper by ctrl + alt + click
fun registerUiDropperAction() {
com.intellij.internal.inspector.UiDropperAction.setClickAction(this)
}
fun recordAction() {
}
fun clickCmp(cmp: Component, e: com.intellij.openapi.actionSystem.AnActionEvent) {
when (cmp) {
is JButton -> write(Templates.findAndClickButton(cmp.text))
is com.intellij.ui.components.labels.ActionLink -> write(Templates.clickActionLink(cmp.text))
is JTextField -> {
write(Templates.findJTextField())
}
is com.intellij.ui.components.JBList -> {
val itemName = e.dataContext.getData("ItemName") as String
if (isPopupList(cmp))
write(Templates.clickPopupItem(itemName))
else
write(Templates.clickListItem(itemName))
}
}
}
private fun isPopupList(cmp: Component) = cmp.javaClass.name.toLowerCase().contains("listpopup")
fun checkContext(cmp: Component) {
cmp as JComponent
if (isPopupList(cmp)) return //dont' change context for a popup menu
if (currentContextComponent != null && !cmp.rootPane.equals(currentContextComponent)) {
write(currentContext.closeContext())
}
if (currentContextComponent == null || !cmp.rootPane.equals(currentContextComponent)) {
currentContextComponent = cmp.rootPane
when (cmp.rootPane.parent) {
is JDialog -> {
if ((cmp.rootPane.parent as JDialog).title.equals(com.intellij.ide.IdeBundle.message("title.new.project")))
write(currentContext.projectWizardContextStart())
else
write(currentContext.dialogContextStart((cmp.rootPane.parent as JDialog).title))
}
is com.intellij.openapi.wm.impl.welcomeScreen.FlatWelcomeFrame -> write(currentContext.welcomeFrameStart())
is JFrame -> println("is JFrame")
}
}
}
fun write(str: String) {
println(str)
}
}
//TEMPLATES
private object Templates {
fun findDialog(name: String, title: String?) = "val ${name} = DialogFixture.find(robot(), \"${title}\")"
fun withDialog(name: String) = "with (${name}){"
fun findProjectWizard(name: String) = "val ${name} = findNewProjectWizard()"
fun withProjectWizard(name: String) = "with (${name}){"
fun findWelcomeFrame(name: String) = "val ${name} = findWelcomeFrame()"
fun withWelcomeFrame(name: String) = "with (${name}){"
fun findAndClickButton(text: String) = "GuiTests.findAndClickButton(this, \"${text}\")"
fun clickActionLink(text: String) = "ActionLinkFixture.findActionLinkByName(\"${text}\", robot(), this.target()).click()"
fun clickPopupItem(itemName: String) = "GuiTests.clickPopupMenuItem(\"${itemName}\", this.target(), robot())"
fun clickListItem(name: String) = "clickListItem(\"${name}\", robot(), this.target())"
fun findJTextField() = "val textField = myRobot.finder().findByType(JTextField::class.java)"
fun findJTextFieldByLabel(labelText: String) = "val textField = findTextField(\"${labelText}\").click()"
}
private class Contexts() {
enum class Type {DIALOG, WELCOME_FRAME, PROJECT_WIZARD, IDE_FRAME}
var dialogCount = 0
var currentContextType: Type? = null
fun dialogContextStart(title: String): String {
currentContextType = Type.DIALOG
val name = "dialog${dialogCount++}"
val findDialog = Templates.findDialog(name, title)
val withDialog = Templates.withDialog(name)
return findDialog + "\n" + withDialog
}
fun projectWizardContextStart(): String {
currentContextType = Type.PROJECT_WIZARD
val name = "projectWizard"
val findProjectWizard = Templates.findProjectWizard(name)
val withProjectWizard = Templates.withProjectWizard(name)
return findProjectWizard + "\n" + withProjectWizard
}
fun welcomeFrameStart(): String {
currentContextType = Type.WELCOME_FRAME
val name = "welcomeFrame"
val findWelcomeFrame = Templates.findWelcomeFrame(name)
var withWelcomeFrame = Templates.withWelcomeFrame(name)
return findWelcomeFrame + "\n" + withWelcomeFrame
}
fun closeContext() = "}"
}
@@ -23,27 +23,29 @@ import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.actionSystem.impl.SimpleDataContext;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.keymap.impl.keyGestures.GestureActionEvent;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.roots.ui.configuration.actions.IconWithTextAction;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.StripeTable;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.wm.IdeGlassPane;
import com.intellij.openapi.wm.impl.IdeGlassPaneImpl;
import com.intellij.ui.*;
import com.intellij.ui.components.JBList;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.ui.components.JBTextField;
import com.intellij.ui.popup.PopupFactoryImpl;
import com.intellij.ui.speedSearch.SpeedSearchUtil;
import com.intellij.util.ExceptionUtil;
import com.intellij.util.Function;
import com.intellij.util.ObjectUtils;
import com.intellij.util.ReflectionUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashMap;
import com.intellij.util.containers.WeakKeyWeakValueHashMap;
import com.intellij.util.ui.*;
import com.intellij.util.ui.tree.TreeUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -63,15 +65,16 @@ import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
import javax.xml.crypto.Data;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.RoundRectangle2D;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import static java.awt.event.MouseEvent.BUTTON1;
import static java.awt.event.MouseEvent.MOUSE_CLICKED;
@@ -125,7 +128,7 @@ public class UiDropperAction extends ToggleAction implements DumbAware {
NotificationType.INFORMATION);
}
}
private static class InspectorWindow extends JDialog {
private InspectorTable myInspectorTable;
private Component myComponent;
@@ -426,6 +429,14 @@ public class UiDropperAction extends ToggleAction implements DumbAware {
setFont(UIUtil.getLabelFont());
}
public MyLabel(String text, JComponent glassPane, int width) {
super(text);
myText = text;
myGlasspane = glassPane;
setForeground(Gray._230);
setFont(new Font(UIUtil.getLabelFont().getName(), Font.PLAIN, 6));
}
public void dispose() {
if (myGlasspane != null) myGlasspane.remove(this);
}
@@ -1019,9 +1030,15 @@ public class UiDropperAction extends ToggleAction implements DumbAware {
JRootPane rootPane = SwingUtilities.getRootPane(jbList);
JComponent glassPane = (JComponent)rootPane.getGlassPane();
if (!(glassPane instanceof IdeGlassPane)) rootPane.setGlassPane(new IdeGlassPaneImpl(rootPane));
myHighlightComponent = new HighlightComponent(new JBColor(JBColor.GREEN, JBColor.RED), glassPane, jbList);
myLabel = new MyLabel("JBList Cell: " + elementAt.getClass().getName() + " (\"" + elementAt.toString() + "\")", glassPane);
if (elementAt instanceof PopupFactoryImpl.ActionItem) {
myLabel = new MyLabel(elementAt.getClass().getName() + " (\"" + elementAt.toString() + "\")", glassPane, cellBounds.width);
} else {
myLabel = new MyLabel("JBList Cell: " + elementAt.getClass().getName() + " (\"" + elementAt.toString() + "\")", glassPane);
}
Point jbListLocationOnRootPane = SwingUtilities.convertPoint(jbList, new Point(0, 0), jbList.getRootPane());
myHighlightComponent.setBounds(jbListLocationOnRootPane.x + cellBounds.x, jbListLocationOnRootPane.y + cellBounds.y, cellBounds.width, cellBounds.height);
@@ -1065,6 +1082,22 @@ public class UiDropperAction extends ToggleAction implements DumbAware {
glassPane.repaint();
}
@Nullable
private static String getCellText(@NotNull JBList jbList, @NotNull Point pointOnList){
int index = jbList.locationToIndex(pointOnList);
Rectangle cellBounds = jbList.getCellBounds(index, index);
if (cellBounds.contains(pointOnList)) {
Object elementAt = jbList.getModel().getElementAt(index);
if (elementAt instanceof PopupFactoryImpl.ActionItem) {
return ((PopupFactoryImpl.ActionItem)elementAt).getText();
}
else {
return elementAt.toString();
}
}
return null;
}
private void cleanupHighlighting() {
if (myHighlightComponent != null) {
myHighlightComponent.dispose();
@@ -1166,7 +1199,11 @@ public class UiDropperAction extends ToggleAction implements DumbAware {
//user click
if (me.getClickCount() == 1 && me.getID() == MOUSE_CLICKED && me.getButton() == BUTTON1) {
if (clickAction != null) {
DataContext dataContext = SimpleDataContext.getSimpleContext("Component", component);
Map<String, Object> dataMap = new HashMap<>();
dataMap.put("Component", component);
if (component instanceof JBList)
dataMap.put("ItemName", getCellText((JBList)component, mousePoint));
DataContext dataContext = SimpleDataContext.getSimpleContext(dataMap, null);
AnActionEvent event = AnActionEvent.createFromDataContext(UI_DROPPER_PLACE, null, dataContext);
clickAction.actionPerformed(event);
return;
@@ -100,6 +100,9 @@
<xi:include href="/META-INF/dvcs.xml" xpointer="xpointer(/idea-plugin/*)">
<xi:fallback/>
</xi:include>
<xi:include href="/META-INF/community-tests.xml" xpointer="xpointer(/idea-plugin/*)">
<xi:fallback/>
</xi:include>
<xi:include href="built-in-server.xml" xpointer="xpointer(/idea-plugin/*)"/>
</idea-plugin>
@@ -13,6 +13,9 @@
<xi:include href="/META-INF/dvcs.xml" xpointer="xpointer(/idea-plugin/*)">
<xi:fallback/>
</xi:include>
<xi:include href="/META-INF/community-tests.xml" xpointer="xpointer(/idea-plugin/*)">
<xi:fallback/>
</xi:include>
<extensionPoints>
<xi:include href="/META-INF/PlatformExtensionPoints.xml" xpointer="xpointer(/idea-plugin/extensionPoints/*)"/>
@@ -396,6 +396,9 @@
<xi:include href="/META-INF/dvcs.xml" xpointer="xpointer(/idea-plugin/*)">
<xi:fallback/>
</xi:include>
<xi:include href="/META-INF/community-tests.xml" xpointer="xpointer(/idea-plugin/*)">
<xi:fallback/>
</xi:include>
<xi:include href="/META-INF/XmlPlugin.xml" xpointer="xpointer(/idea-plugin/*)"/>
<xi:include href="/META-INF/JsonPlugin.xml" xpointer="xpointer(/idea-plugin/*)">