Skip to main content
Glama
AndroidWebViewHierarchyClientTest.kt7.46 kB
package maestro.android.chromedevtools import com.google.common.truth.Truth.assertThat import maestro.TreeNode import maestro.UiElement.Companion.toUiElementOrNull import org.junit.jupiter.api.Test class AndroidWebViewHierarchyClientTest { @Test fun testMergeHierarchies1() { testMergeHierarchies( "[1-2,text=foo]", "", "[1-2,text=foo]" ) } @Test fun testMergeHierarchies2() { testMergeHierarchies( "[1-2,text=foo]", "[1-2,text=bar]", "[1-2,text=foo][1-2,text=bar]" ) } @Test fun testMergeHierarchies3() { testMergeHierarchies( "[1-3,text=foo]", "[2-4,text=foo]", "[1-3,text=foo]" ) } @Test fun testMergeHierarchies4() { testMergeHierarchies( "[1-2,text=foobar]", "[1-2,text=foo]", "[1-2,text=foobar]" ) } @Test fun testMergeHierarchies5() { testMergeHierarchies( "[1-3,text=foobar]", "[2-4,text=foo]", "[1-3,text=foobar]" ) } @Test fun testMergeHierarchies6() { testMergeHierarchies( "[1-2,text=foobar]", "[2-4,text=foo]", "[1-2,text=foobar][2-4,text=foo]" ) } @Test fun testMergeHierarchies7() { testMergeHierarchies( "[1-2,text=foo]", "[1-2,id=foo]", "[1-2,text=foo,id=foo]" ) } @Test fun testMergeHierarchies8() { testMergeHierarchies( "[1-2,text=foo][2-3,text=bar]", "[2-3,text=foo]", "[1-2,text=foo][2-3,text=bar][2-3,text=foo]" ) } @Test fun testMergeHierarchies9() { testMergeHierarchies( "[1-2,text=foo,id=bar]", "[1-2,text=foo]", "[1-2,text=foo,id=bar]" ) } @Test fun testMergeHierarchies10() { testMergeHierarchies( "[1-3,text=foobar]", "[2-4,text=foo,id=bar]", "[1-3,text=foobar,id=bar]" ) } @Test fun testMergeHierarchies11() { testMergeHierarchies( "[1-2,text=foo][2-3,text=bar]", "[1-2,id=foo][2-3,id=bar]", "[1-2,text=foo,id=foo][2-3,text=bar,id=bar]" ) } @Test fun testMergeHierarchies12() { testMergeHierarchies( "[1-2,text=foo]", "[2-3,text=foo]", "[1-2,text=foo][2-3,text=foo]" ) } @Test fun testMergeHierarchies13() { testMergeHierarchies( "[1-2,text=foo]", "[2-3,text=]", "[1-2,text=foo]" ) } @Test fun testMergeHierarchies14() { testMergeHierarchies( "[1-2,text=foo,id=][3-4,text=,id=bar]", "[1-2,text=foo,id=bar][3-4,text=foo,id=bar]", "[1-2,text=foo,id=bar][3-4,text=foo,id=bar]" ) } @Test fun testMergeHierarchies15() { testMergeHierarchies( "[1-2,accessibilityText=foo]", "[1-2,text=foo,id=bar]", "[1-2,accessibilityText=foo,id=bar]" ) } @Test fun testMergeHierarchies16() { testMergeHierarchies( "[1-2,hintText=foo]", "[1-2,text=foo,id=bar]", "[1-2,hintText=foo,id=bar]" ) } private fun testMergeHierarchies( base: String, webview: String, expected: String, ) { val baseHierarchy = stringToHierarchy(base) val webviewHierarchy = stringToHierarchy(webview) val mergedHierarchy = AndroidWebViewHierarchyClient.mergeHierarchies(baseHierarchy, webviewHierarchy.children) assertThat(hierarchyToString(mergedHierarchy)).isEqualTo(expected) } @Test fun stringToHierarchyTest() { val hierarchy1 = stringToHierarchy("[0-1]") assertThat(hierarchy1.children).hasSize(1) assertThat(hierarchy1.children[0]).isEqualTo(TreeNode( attributes = mutableMapOf( "bounds" to "[0,0][1,100]" ) )) assertThat(hierarchyToString(hierarchy1)).isEqualTo("[0-1]") val hierarchy2 = stringToHierarchy("[1-2,text=foo]") assertThat(hierarchy2.children).containsExactly(TreeNode( attributes = mutableMapOf( "text" to "foo", "bounds" to "[1,0][2,100]" ) )).inOrder() assertThat(hierarchyToString(hierarchy2)).isEqualTo("[1-2,text=foo]") val hierarchy3 = stringToHierarchy("[1-2,text=foo,id=bar]") assertThat(hierarchy3.children).containsExactly(TreeNode( attributes = mutableMapOf( "text" to "foo", "resource-id" to "bar", "bounds" to "[1,0][2,100]" ) )).inOrder() assertThat(hierarchyToString(hierarchy3)).isEqualTo("[1-2,text=foo,id=bar]") val hierarchy4 = stringToHierarchy("[1-2,text=foo,id=bar][2-3,text=baz,id=boo]") assertThat(hierarchy4.children).containsExactly(TreeNode( attributes = mutableMapOf( "text" to "foo", "resource-id" to "bar", "bounds" to "[1,0][2,100]" ) ), TreeNode( attributes = mutableMapOf( "text" to "baz", "resource-id" to "boo", "bounds" to "[2,0][3,100]" ) )).inOrder() assertThat(hierarchyToString(hierarchy4)).isEqualTo("[1-2,text=foo,id=bar][2-3,text=baz,id=boo]") val hierarchy5 = stringToHierarchy("") assertThat(hierarchy5.children).isEmpty() assertThat(hierarchyToString(hierarchy5)).isEqualTo("") } private fun hierarchyToString(hierarchy: TreeNode): String { return hierarchy.aggregate().mapNotNull { it.toUiElementOrNull() }.map { assertThat(it.bounds.y).isEqualTo(0) assertThat(it.bounds.height).isEqualTo(100) val range = it.bounds.x.toString() + "-" + (it.bounds.x + it.bounds.width).toString() val attributes = it.treeNode.attributes.entries.filter { it.key != "bounds" }.map { (key, value) -> val finalKey = when (key) { "resource-id" -> "id" else -> key } "$finalKey=$value" } return@map "[${(listOf(range) + attributes).joinToString(",")}]" }.joinToString("") } private fun stringToHierarchy(hierarchy: String): TreeNode { val nodes = hierarchy.split("]") .map { it.trim('[', ']') } .filter { it.isNotEmpty() } .map { val parts = it.split(',') val (start, end) = parts.first().split('-').map(String::toInt) val bounds = "[$start,0][$end,100]" val attributes = parts.drop(1).map { val (key, value) = it.split("=") val finalKey = when (key) { "id" -> "resource-id" else -> key } finalKey to value }.toMap() + mapOf("bounds" to bounds) TreeNode(attributes.toMutableMap()) } return TreeNode(children = nodes) } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mobile-dev-inc/Maestro'

If you have feedback or need assistance with the MCP directory API, please join our Discord server