appium-espresso-driver 2.13.2 → 2.13.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/espresso-server/app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk +0 -0
- package/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/helpers/ComposeNodeFinder.kt +6 -2
- package/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/model/SourceDocument.kt +15 -17
- package/espresso-server/app/src/androidTest/java/io/appium/espressoserver/lib/viewmatcher/WithXPath.kt +17 -3
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
|
Binary file
|
|
@@ -26,6 +26,7 @@ import io.appium.espressoserver.lib.handlers.exceptions.StaleElementException
|
|
|
26
26
|
import io.appium.espressoserver.lib.model.Locator
|
|
27
27
|
import io.appium.espressoserver.lib.model.SourceDocument
|
|
28
28
|
import io.appium.espressoserver.lib.model.AttributesEnum
|
|
29
|
+
import io.appium.espressoserver.lib.model.compileXpathExpression
|
|
29
30
|
import io.appium.espressoserver.lib.viewmatcher.fetchIncludedAttributes
|
|
30
31
|
|
|
31
32
|
/**
|
|
@@ -63,9 +64,12 @@ fun semanticsMatcherForLocator(locator: Locator): SemanticsMatcher =
|
|
|
63
64
|
}
|
|
64
65
|
|
|
65
66
|
private fun hasXpath(locator: Locator): SemanticsMatcher {
|
|
67
|
+
val xpath = locator.value!!
|
|
68
|
+
val expression = compileXpathExpression(xpath)
|
|
69
|
+
val attributes = fetchIncludedAttributes(xpath)
|
|
66
70
|
val matchingIds = SourceDocument(
|
|
67
|
-
locator.elementId?.let { getSemanticsNode(it) },
|
|
68
|
-
).
|
|
71
|
+
locator.elementId?.let { getSemanticsNode(it) }, attributes
|
|
72
|
+
).findMatchingNodeIds(expression, AttributesEnum.RESOURCE_ID.toString())
|
|
69
73
|
|
|
70
74
|
return SemanticsMatcher("Matches Xpath ${locator.value}") {
|
|
71
75
|
matchingIds.contains(it.id)
|
|
@@ -80,6 +80,12 @@ private fun toXmlNodeName(className: String?): String {
|
|
|
80
80
|
return fixedName
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
fun compileXpathExpression(selector: String): XPathExpression =
|
|
84
|
+
try {
|
|
85
|
+
XPATH.compile(selector)
|
|
86
|
+
} catch (xe: XPathExpressionException) {
|
|
87
|
+
throw XPathLookupException(selector, xe.message!!)
|
|
88
|
+
}
|
|
83
89
|
|
|
84
90
|
class SourceDocument constructor(
|
|
85
91
|
private val root: Any? = null,
|
|
@@ -324,8 +330,8 @@ class SourceDocument constructor(
|
|
|
324
330
|
throw AppiumException(lastError!!)
|
|
325
331
|
}
|
|
326
332
|
|
|
327
|
-
private fun rootSemanticNodes(): List<SemanticsNode>
|
|
328
|
-
|
|
333
|
+
private fun rootSemanticNodes(): List<SemanticsNode> =
|
|
334
|
+
try {
|
|
329
335
|
listOf(EspressoServerRunnerTest.composeTestRule.onRoot(useUnmergedTree = true).fetchSemanticsNode())
|
|
330
336
|
} catch (e: AssertionError) {
|
|
331
337
|
// Ideally there should be on `root` node but on some cases e.g:overlays screen, there can be more than 1 root.
|
|
@@ -337,7 +343,6 @@ class SourceDocument constructor(
|
|
|
337
343
|
} as SelectionResult
|
|
338
344
|
result.selectedNodes
|
|
339
345
|
}
|
|
340
|
-
}
|
|
341
346
|
|
|
342
347
|
private fun performCleanup() {
|
|
343
348
|
tmpXmlName?.let {
|
|
@@ -346,8 +351,8 @@ class SourceDocument constructor(
|
|
|
346
351
|
}
|
|
347
352
|
}
|
|
348
353
|
|
|
349
|
-
fun toXMLString(): String
|
|
350
|
-
|
|
354
|
+
fun toXMLString(): String =
|
|
355
|
+
RESOURCES_GUARD.withPermit({
|
|
351
356
|
toStream().use { xmlStream ->
|
|
352
357
|
val sb = StringBuilder()
|
|
353
358
|
val reader = BufferedReader(InputStreamReader(xmlStream, XML_ENCODING))
|
|
@@ -359,24 +364,17 @@ class SourceDocument constructor(
|
|
|
359
364
|
sb.toString()
|
|
360
365
|
}
|
|
361
366
|
}, { performCleanup() })
|
|
362
|
-
}
|
|
363
367
|
|
|
364
|
-
fun findViewsByXPath(
|
|
365
|
-
|
|
368
|
+
fun findViewsByXPath(expression: XPathExpression): List<View> =
|
|
369
|
+
findMatchingNodeIds(expression, VIEW_INDEX).map { viewMap.get(it) }
|
|
366
370
|
|
|
367
|
-
fun
|
|
368
|
-
|
|
369
|
-
XPATH.compile(xpathSelector)
|
|
370
|
-
} catch (xe: XPathExpressionException) {
|
|
371
|
-
throw XPathLookupException(xpathSelector, xe.message!!)
|
|
372
|
-
}
|
|
373
|
-
return RESOURCES_GUARD.withPermit({
|
|
371
|
+
fun findMatchingNodeIds(expression: XPathExpression, attributeName: String): List<Int> =
|
|
372
|
+
RESOURCES_GUARD.withPermit({
|
|
374
373
|
toStream().use { xmlStream ->
|
|
375
|
-
val list =
|
|
374
|
+
val list = expression.evaluate(InputSource(xmlStream), XPathConstants.NODESET) as NodeList
|
|
376
375
|
(0 until list.length).map { index ->
|
|
377
376
|
list.item(index).attributes.getNamedItem(attributeName).nodeValue.toInt()
|
|
378
377
|
}
|
|
379
378
|
}
|
|
380
379
|
}, { performCleanup() })
|
|
381
|
-
}
|
|
382
380
|
}
|
|
@@ -16,12 +16,15 @@
|
|
|
16
16
|
package io.appium.espressoserver.lib.viewmatcher
|
|
17
17
|
|
|
18
18
|
import android.view.View
|
|
19
|
+
import io.appium.espressoserver.lib.helpers.extensions.withPermit
|
|
19
20
|
import io.appium.espressoserver.lib.model.SourceDocument
|
|
20
21
|
import io.appium.espressoserver.lib.model.AttributesEnum
|
|
21
22
|
import io.appium.espressoserver.lib.model.EspressoAttributes
|
|
23
|
+
import io.appium.espressoserver.lib.model.compileXpathExpression
|
|
22
24
|
import org.hamcrest.Description
|
|
23
25
|
import org.hamcrest.Matcher
|
|
24
26
|
import org.hamcrest.TypeSafeMatcher
|
|
27
|
+
import java.util.concurrent.Semaphore
|
|
25
28
|
|
|
26
29
|
fun fetchIncludedAttributes(xpath: String): Set<AttributesEnum>? {
|
|
27
30
|
if (xpath.contains("@*")) {
|
|
@@ -37,13 +40,24 @@ fun fetchIncludedAttributes(xpath: String): Set<AttributesEnum>? {
|
|
|
37
40
|
}
|
|
38
41
|
|
|
39
42
|
fun withXPath(root: View?, xpath: String, index: Int? = null): Matcher<View> {
|
|
43
|
+
val expression = compileXpathExpression(xpath)
|
|
44
|
+
val attributes = fetchIncludedAttributes(xpath)
|
|
40
45
|
val matchedXPathViews = mutableListOf<View>()
|
|
46
|
+
var didLookup = false
|
|
47
|
+
val lookupGuard = Semaphore(1)
|
|
41
48
|
return object : TypeSafeMatcher<View>() {
|
|
42
49
|
override fun matchesSafely(item: View): Boolean {
|
|
50
|
+
lookupGuard.withPermit {
|
|
51
|
+
if (!didLookup) {
|
|
52
|
+
matchedXPathViews.addAll(
|
|
53
|
+
SourceDocument(root ?: item.rootView, attributes).findViewsByXPath(expression)
|
|
54
|
+
)
|
|
55
|
+
didLookup = true
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
43
59
|
if (matchedXPathViews.isEmpty()) {
|
|
44
|
-
|
|
45
|
-
SourceDocument(root ?: item.rootView, fetchIncludedAttributes(xpath)).findViewsByXPath(xpath)
|
|
46
|
-
)
|
|
60
|
+
return false
|
|
47
61
|
}
|
|
48
62
|
|
|
49
63
|
return if (index != null) {
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "appium-espresso-driver",
|
|
3
|
-
"version": "2.13.
|
|
3
|
+
"version": "2.13.3",
|
|
4
4
|
"lockfileVersion": 2,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "appium-espresso-driver",
|
|
9
|
-
"version": "2.13.
|
|
9
|
+
"version": "2.13.3",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@babel/runtime": "^7.4.3",
|