[gui-test] Corrected way to select a node in the tree.

This commit is contained in:
Viktoria.Shirunova
2018-07-10 23:32:36 +03:00
parent d6617dfcce
commit c77dfa7f8c
6 changed files with 132 additions and 42 deletions
@@ -9,9 +9,9 @@ import com.intellij.testGuiFramework.impl.GuiRobotHolder
import com.intellij.testGuiFramework.impl.GuiTestUtilKt
import org.fest.assertions.Assertions
import org.fest.reflect.core.Reflection
import org.fest.swing.cell.JTreeCellReader
import org.fest.swing.core.MouseButton
import org.fest.swing.core.MouseClickInfo
import org.fest.swing.core.Robot
import org.fest.swing.driver.ComponentPreconditions
import org.fest.swing.driver.JTreeDriver
import org.fest.swing.driver.JTreeLocation
@@ -22,10 +22,10 @@ import org.fest.swing.util.Pair
import org.fest.swing.util.Triple
import java.awt.Point
import java.awt.Rectangle
import org.fest.swing.core.Robot
import javax.swing.JPopupMenu
import javax.swing.JTree
import javax.swing.plaf.basic.BasicTreeUI
import javax.swing.tree.DefaultMutableTreeNode
import javax.swing.tree.TreePath
open class ExtendedJTreeDriver(robot: Robot = GuiRobotHolder.robot) : JTreeDriver(robot) {
@@ -33,14 +33,13 @@ open class ExtendedJTreeDriver(robot: Robot = GuiRobotHolder.robot) : JTreeDrive
// TODO: check can we remove jTreeLocation and use local variables instead of
private val jTreeLocation = JTreeLocation()
private fun JTree.getCellReader(): JTreeCellReader {
init {
val resultReader = when (javaClass.name) {
"com.intellij.openapi.options.newEditor.SettingsTreeView\$MyTree" -> SettingsTreeCellReader()
"com.intellij.ide.projectView.impl.ProjectViewPane\$1" -> ProjectTreeCellReader()
else -> ExtendedJTreeCellReader()
}
replaceCellReader(resultReader)
return resultReader
this.replaceCellReader(resultReader)
}
fun clickPath(tree: JTree, treePath: TreePath, mouseClickInfo: MouseClickInfo): Unit =
@@ -150,7 +149,8 @@ open class ExtendedJTreeDriver(robot: Robot = GuiRobotHolder.robot) : JTreeDrive
/**
* node that has as child LoadingNode
*/
class LoadingNodeException(val node: Any, var treePath: TreePath?) : Exception("Meet loading node: $node")
class LoadingNodeException(val node: Any, var treePath: TreePath?) :
Exception("Meet loading node: $node (${treePath?.path?.joinToString()}")
private fun JTree.childCount(path: TreePath): Int {
return GuiTestUtilKt.computeOnEdt {
@@ -168,11 +168,15 @@ open class ExtendedJTreeDriver(robot: Robot = GuiRobotHolder.robot) : JTreeDrive
}
fun expandPath(tree: JTree, treePath: TreePath) {
// do not try to expand leaf
if(tree.model.isLeaf(treePath.lastPathComponent)) return
val info = tree.scrollToMatchingPathAndGetToggleInfo(treePath)
if (!info.first) tree.toggleCell(info.second!!, info.third)
}
fun collapsePath(tree: JTree, treePath: TreePath) {
// do not try to collapse leaf
if(tree.model.isLeaf(treePath.lastPathComponent)) return
val info = tree.scrollToMatchingPathAndGetToggleInfo(treePath)
if (info.first) tree.toggleCell(info.second!!, info.third)
}
@@ -238,16 +242,45 @@ open class ExtendedJTreeDriver(robot: Robot = GuiRobotHolder.robot) : JTreeDrive
drop(tree, tree.scrollToMatchingPath(treePath).second!!)
}
fun getPathStrings(tree: JTree, path: TreePath) : List<String>{
var myPath = path
val result = mutableListOf<String>()
while (myPath.pathCount != 1 || (tree.isRootVisible && myPath.pathCount == 1)) {
val valueAt = tree.getCellReader().valueAt(tree, myPath.lastPathComponent) ?: "null"
result.add(0, valueAt)
if (myPath.pathCount == 1) break
else myPath = myPath.parentPath
fun findPath(tree: JTree, stringPath: List<String>, predicate: FinderPredicate = ExtendedJTreePathFinder.predicateEquality): TreePath {
fun <T> List<T>.list2tree() = map { subList(0, indexOf(it) + 1) }
lateinit var path: TreePath
stringPath
.list2tree()
.forEach {
path = ExtendedJTreePathFinder(tree)
.findMatchingPathByPredicate(predicate = predicate, pathStrings = *it.toTypedArray())
expandPath(tree, path)
}
return path
}
fun findPathToNode(tree: JTree, node: String, predicate: FinderPredicate = ExtendedJTreePathFinder.predicateEquality): TreePath {
val result: MutableList<String> = mutableListOf()
var currentNode = tree.model.root as DefaultMutableTreeNode
val e = currentNode.preorderEnumeration()
while (e.hasMoreElements()) {
currentNode = e.nextElement() as DefaultMutableTreeNode
if (predicate(currentNode.toString(), node)) {
break
}
}
result.add(0, currentNode.toString())
while (currentNode.parent != null) {
currentNode = currentNode.parent as DefaultMutableTreeNode
result.add(0, currentNode.toString())
}
return findPath(tree, result, predicate)
}
fun exists(tree: JTree, pathStrings: List<String>, predicate: FinderPredicate = ExtendedJTreePathFinder.predicateEquality): Boolean {
return try {
findPath(tree, pathStrings, predicate)
true
}
catch (e: LocationUnavailableException){
false
}
return result.toList()
}
} // end of class
@@ -2,19 +2,21 @@
package com.intellij.testGuiFramework.fixtures
import com.intellij.testGuiFramework.driver.CheckboxTreeDriver
import com.intellij.testGuiFramework.driver.ExtendedJTreePathFinder
import com.intellij.testGuiFramework.driver.FinderPredicate
import com.intellij.testGuiFramework.fixtures.extended.ExtendedJTreePathFixture
import com.intellij.testGuiFramework.framework.GuiTestUtil
import com.intellij.testGuiFramework.impl.GuiRobotHolder
import com.intellij.ui.CheckboxTree
import org.fest.swing.core.Robot
import javax.swing.tree.TreePath
class CheckboxTreeFixture(
checkboxTree: CheckboxTree,
path: TreePath,
stringPath: List<String>,
predicate: FinderPredicate = ExtendedJTreePathFinder.predicateEquality,
robot: Robot = GuiRobotHolder.robot,
private val myDriver: CheckboxTreeDriver = CheckboxTreeDriver(robot)
) : ExtendedJTreePathFixture(checkboxTree, path, robot) {
) : ExtendedJTreePathFixture(checkboxTree, stringPath, predicate, robot, myDriver) {
init {
this.replaceDriverWith(myDriver)
@@ -1,9 +1,10 @@
// 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.
// 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.
// 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.extended
import com.intellij.testGuiFramework.driver.ExtendedJTreeDriver
import com.intellij.testGuiFramework.driver.ExtendedJTreePathFinder
import com.intellij.testGuiFramework.driver.FinderPredicate
import com.intellij.testGuiFramework.framework.GuiTestUtil
import com.intellij.testGuiFramework.impl.GuiRobotHolder
import org.fest.swing.core.MouseButton
import org.fest.swing.core.MouseClickInfo
@@ -12,20 +13,33 @@ import org.fest.swing.exception.LocationUnavailableException
import org.fest.swing.fixture.JTreeFixture
import javax.swing.JPopupMenu
import javax.swing.JTree
import javax.swing.tree.DefaultMutableTreeNode
import javax.swing.tree.TreePath
open class ExtendedJTreePathFixture(
val tree: JTree,
val path: TreePath,
private val stringPath: List<String>,
private val predicate: FinderPredicate = ExtendedJTreePathFinder.predicateEquality,
robot: Robot = GuiRobotHolder.robot,
private val myDriver: ExtendedJTreeDriver = ExtendedJTreeDriver(robot)
) : JTreeFixture(robot, tree) {
constructor(tree: JTree, path: TreePath, predicate: FinderPredicate, robot: Robot, driver: ExtendedJTreeDriver) :
this(tree, path.path.map { it.toString() }.toList(), predicate, robot, driver)
init {
replaceDriverWith(myDriver)
}
private val cachePaths = mutableMapOf<List<String>, TreePath>()
protected val path: TreePath
get() {
return if (!cachePaths.containsKey(stringPath))
expandAndGetPathStepByStep(stringPath)
else
cachePaths.getValue(stringPath)
}
/**
* Create a new object of ExtendedJTreePathFixture for a new path
* It's supposed the new path in the same tree
@@ -33,8 +47,7 @@ open class ExtendedJTreePathFixture(
* @throws LocationUnavailableException if path not found
* */
fun path(vararg pathStrings: String): ExtendedJTreePathFixture {
val newPath = ExtendedJTreePathFinder(tree).findMatchingPath(*pathStrings)
return ExtendedJTreePathFixture(tree, newPath, robot(), myDriver)
return ExtendedJTreePathFixture(tree, pathStrings.toList(), predicate, robot(), myDriver)
}
/**
@@ -43,13 +56,25 @@ open class ExtendedJTreePathFixture(
* It's supposed the new path in the same tree
* @param node one node value somewhere whithin the same tree
* @throws LocationUnavailableException if node not found
* TODO complete
* */
fun pathToNode(node: String): ExtendedJTreePathFixture{
val newPath = ExtendedJTreePathFinder(tree).findPathToNode(node)
return ExtendedJTreePathFixture(tree, newPath, robot(), myDriver)
val newPath = myDriver.findPathToNode(tree, node, predicate)
return ExtendedJTreePathFixture(tree, newPath, predicate, robot(), myDriver)
}
fun hasPath(vararg pathStrings: String):Boolean = ExtendedJTreePathFinder(tree).exists(*pathStrings)
fun hasPath(vararg pathStrings: String): Boolean =
ExtendedJTreePathFixture(tree, pathStrings.toList(), predicate, robot(), myDriver).hasPath()
fun hasPath(): Boolean {
return try {
path
true
}
catch (e: Exception) {
false
}
}
fun clickPath(mouseClickInfo: MouseClickInfo): Unit = myDriver.clickPath(tree, path, mouseClickInfo)
@@ -60,7 +85,31 @@ open class ExtendedJTreePathFixture(
fun rightClickPath(): Unit = myDriver.rightClickPath(tree, path)
fun expandPath(): Unit = myDriver.expandPath(tree, path)
fun expandPath() {
myDriver.expandPath(tree, path)
}
protected fun expandAndGetPathStepByStep(stringPath: List<String>): TreePath {
fun <T> List<T>.list2tree() = map { subList(0, indexOf(it) + 1) }
if (!cachePaths.containsKey(stringPath)){
var partialPath: TreePath? = null
for (partialList in stringPath.list2tree()) {
GuiTestUtil.pause(condition = "wait to find a correct path to click", timeoutSeconds = 2L) {
try {
partialPath = ExtendedJTreePathFinder(tree)
.findMatchingPathByPredicate(predicate = predicate, pathStrings = *partialList.toTypedArray())
partialPath != null
}
catch (e: Exception) {
false
}
}
cachePaths[partialList] = partialPath!!
myDriver.expandPath(tree, cachePaths.getValue(partialList))
}
}
return cachePaths.getValue(stringPath)
}
fun collapsePath(): Unit = myDriver.collapsePath(tree, path)
@@ -73,5 +122,5 @@ open class ExtendedJTreePathFixture(
fun drop(): Unit = myDriver.drop(tree, path)
fun getPathStrings(): List<String> = myDriver.getPathStrings(tree, path)
fun getPathStrings(): List<String> = path.path.map { it.toString() }
}
@@ -742,10 +742,10 @@ object GuiTestUtil {
return JTextComponentFixture(GuiRobotHolder.robot, jTextComponent)
}
fun jTreePath(container: Container,
timeout: Long,
vararg pathStrings: String,
predicate: FinderPredicate = ExtendedJTreePathFinder.predicateEquality): ExtendedJTreePathFixture {
fun jTreeComponent(container: Container,
timeout: Long,
vararg pathStrings: String,
predicate: FinderPredicate = ExtendedJTreePathFinder.predicateEquality): JTree {
val myTree: JTree?
try {
myTree = if (pathStrings.isEmpty()) {
@@ -754,7 +754,7 @@ object GuiTestUtil {
else {
waitUntilFound(GuiRobotHolder.robot, container,
GuiTestUtilKt.typeMatcher(JTree::class.java) {
ExtendedJTreePathFinder(it).existsByPredicate(pathStrings = *pathStrings, predicate = predicate)
ExtendedJTreePathFixture(it, pathStrings.toList(), predicate).hasPath()
},
timeout.toFestTimeout())
}
@@ -762,8 +762,7 @@ object GuiTestUtil {
catch (e: WaitTimedOutError) {
throw ComponentLookupException("""JTree "${if (pathStrings.isNotEmpty()) "by path ${pathStrings.joinToString()}" else ""}"""")
}
return ExtendedJTreePathFixture(myTree, ExtendedJTreePathFinder(myTree)
.findMatchingPathByPredicate(pathStrings = *pathStrings, predicate = predicate))
return myTree
}
//*********COMMON FUNCTIONS WITHOUT CONTEXT
@@ -263,12 +263,12 @@ fun <S, C : Component> ComponentFixture<S, C>.jTree(
timeout: Long = defaultTimeout,
predicate: FinderPredicate = ExtendedJTreePathFinder.predicateEquality
): ExtendedJTreePathFixture =
if (target() is Container) GuiTestUtil.jTreePath(
if (target() is Container) ExtendedJTreePathFixture(GuiTestUtil.jTreeComponent(
container = target() as Container,
timeout = timeout,
pathStrings = *pathStrings,
predicate = predicate
)
), pathStrings.toList(), predicate)
else throw unableToFindComponent("""JTree "${if (pathStrings.isNotEmpty()) "by path $pathStrings" else ""}"""")
/**
@@ -284,14 +284,13 @@ fun <S, C : Component> ComponentFixture<S, C>.checkboxTree(
predicate: FinderPredicate = ExtendedJTreePathFinder.predicateEquality
): CheckboxTreeFixture =
if (target() is Container) {
val extendedJTreePathFixture = GuiTestUtil.jTreePath(
val tree = GuiTestUtil.jTreeComponent(
container = target() as Container,
timeout = timeout,
predicate = predicate,
pathStrings = *pathStrings
)
if (extendedJTreePathFixture.tree !is CheckboxTree) throw ComponentLookupException("Found JTree but not a CheckboxTree")
CheckboxTreeFixture(extendedJTreePathFixture.tree, extendedJTreePathFixture.path, robot())
) as? CheckboxTree ?: throw ComponentLookupException("Found JTree but not a CheckboxTree")
CheckboxTreeFixture(tree, pathStrings.toList(), predicate, robot())
}
else throw unableToFindComponent("""CheckboxTree "${if (pathStrings.isNotEmpty()) "by path ${pathStrings.joinToString()}" else ""}"""")
@@ -108,6 +108,14 @@ fun GuiTestCase.testTreeItemExist(name: String, vararg expectedItem: String) {
}
}
/**
* Selects specified [path] in the tree by keyboard searching
* @param path in string form
* @param testCase - test case is required only because of keyboard related functions
*
* TODO: remove [testCase] parameter (so move [shortcut] and [typeText] functions
* out of GuiTestCase)
* */
fun ExtendedJTreePathFixture.selectWithKeyboard(testCase: GuiTestCase, vararg path: String) {
fun currentValue(): String {
val selectedRow = target().selectionRows.first()