Skip to content
This repository has been archived by the owner on Oct 10, 2024. It is now read-only.

Commit

Permalink
input text and tap has now a retry mechanism
Browse files Browse the repository at this point in the history
  • Loading branch information
BenedictP committed Dec 8, 2023
1 parent bf3d59b commit 6f85929
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 126 deletions.
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@

## [Unreleased]

# [1.1.6] - 2023-12-08

Changed:
- Input text has now a retry mechanism
- Tap has now a retry mechanism. It will get a new hierarchy and try to tap again if the tap was not successful.

# [1.1.5] - 2023-10-09

Added:
Expand Down Expand Up @@ -153,7 +159,8 @@ New:

Initial release.

[unreleased]: https://github.com/getyourguide/UiTestGlaze/compare/1.1.5...HEAD
[unreleased]: https://github.com/getyourguide/UiTestGlaze/compare/1.1.6...HEAD
[1.1.5]: https://github.com/getyourguide/UiTestGlaze/releases/tag/1.1.6
[1.1.5]: https://github.com/getyourguide/UiTestGlaze/releases/tag/1.1.5
[1.1.4]: https://github.com/getyourguide/UiTestGlaze/releases/tag/1.1.4
[1.1.3]: https://github.com/getyourguide/UiTestGlaze/releases/tag/1.1.3
Expand Down
2 changes: 1 addition & 1 deletion uiTestGlaze/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ plugins {

ext {
PUBLISH_GROUP_ID = 'io.github.getyourguide'
PUBLISH_VERSION = '1.1.5'
PUBLISH_VERSION = '1.1.6'
PUBLISH_ARTIFACT_ID = 'uitestglaze'
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,74 +5,97 @@ import androidx.test.uiautomator.UiSelector
import kotlin.time.Duration

internal class InputTextHelper(
private val config: UiTestGlaze.Config,
private val getHierarchyHelper: GetHierarchyHelper,
private val findUiElementHelper: FindUiElementHelper,
private val hierarchySettleHelper: HierarchySettleHelper,
private val printHierarchyHelper: PrintHierarchyHelper
) {

fun inputText(
text: String,
uiElementIdentifier: UiElementIdentifier,
device: UiDevice,
inputShouldBeRecognizedTimeout: Duration,
numberOfRetries: Int,
) {
val hierarchy = getHierarchyHelper.getHierarchy(device)
val foundUiElement =
findUiElementHelper.getUiElement(
uiElementIdentifier,
hierarchy,
false,
device,
)
?: throw IllegalStateException("Can not find UiElement to enter text")

when (uiElementIdentifier) {
is UiElementIdentifier.PositionInHierarchy ->
enterText(
uiElementIdentifier.inputIndicatorText,
foundUiElement.text,
foundUiElement.resourceId,
device,
text,
)

is UiElementIdentifier.ChildFrom ->
enterText(
uiElementIdentifier.inputIndicatorText,
foundUiElement.text,
foundUiElement.resourceId,
var currentTry = 0
while (numberOfRetries >= currentTry) {
val hierarchy = getHierarchyHelper.getHierarchy(device)
val foundUiElement =
findUiElementHelper.getUiElement(
uiElementIdentifier,
hierarchy,
false,
device,
text,
)
?: throw IllegalStateException("Can not find UiElement to enter text")

is UiElementIdentifier.Id,
is UiElementIdentifier.TestTag,
-> {
device.findObject(
UiSelector().resourceId(foundUiElement.resourceId)
.instance(uiElementIdentifier.index),
).text = text
if (foundUiElement.text == text) {
return
}

is UiElementIdentifier.Text,
is UiElementIdentifier.TextResource,
is UiElementIdentifier.TextRegex,
-> {
device.findObject(
UiSelector().text(foundUiElement.text).instance(uiElementIdentifier.index),
).text = text
when (uiElementIdentifier) {
is UiElementIdentifier.PositionInHierarchy ->
enterText(
uiElementIdentifier.inputIndicatorText,
foundUiElement.text,
foundUiElement.resourceId,
device,
text,
)

is UiElementIdentifier.ChildFrom ->
enterText(
uiElementIdentifier.inputIndicatorText,
foundUiElement.text,
foundUiElement.resourceId,
device,
text,
)

is UiElementIdentifier.Id,
is UiElementIdentifier.TestTag,
-> {
device.findObject(
UiSelector().resourceId(foundUiElement.resourceId)
.instance(uiElementIdentifier.index),
).text = text
}

is UiElementIdentifier.Text,
is UiElementIdentifier.TextResource,
is UiElementIdentifier.TextRegex,
-> {
device.findObject(
UiSelector().text(foundUiElement.text).instance(uiElementIdentifier.index),
).text = text
}
}
}
val startTime = System.currentTimeMillis()
var hierarchyChanged = false
do {
val hierarchyAfterEnteringText = getHierarchyHelper.getHierarchy(device)
if (hierarchy != hierarchyAfterEnteringText) {
hierarchyChanged = true
break
val startTime = System.currentTimeMillis()
var hierarchyChanged = false
do {
val hierarchyAfterEnteringText = hierarchySettleHelper.waitTillHierarchySettles(
config.loadingResourceIds,
device,
config.waitTillLoadingViewsGoneTimeout,
config.waitTillHierarchySettlesTimeout,
)
printHierarchyHelper.print(hierarchyAfterEnteringText, "After entering text ")
if (hierarchy != hierarchyAfterEnteringText) {
hierarchyChanged = true
break
}
} while ((System.currentTimeMillis() - startTime) < inputShouldBeRecognizedTimeout.inWholeMilliseconds)

if (!hierarchyChanged) {
if (currentTry == numberOfRetries) {
throw IllegalStateException("Timeout hit while waiting for text to appear")
}
currentTry++
} else {
return
}
} while ((System.currentTimeMillis() - startTime) < inputShouldBeRecognizedTimeout.inWholeMilliseconds)
if (!hierarchyChanged) {
throw IllegalStateException("Timeout hit while waiting for hierarchy to settle")
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ internal class TapHelper(
private val config: UiTestGlaze.Config,
private val findUiElementHelper: FindUiElementHelper,
private val hierarchySettleHelper: HierarchySettleHelper,
private val getHierarchyHelper: GetHierarchyHelper,
) {

fun tap(
Expand All @@ -16,23 +15,47 @@ internal class TapHelper(
longPress: Boolean,
offsetX: Int,
offsetY: Int,
hierarchy: TreeNode,
device: UiDevice,
) {
val foundUiElement =
findUiElementHelper.getUiElement(
uiElementIdentifier,
hierarchy,
optional,
device,
) ?: return
tapOnTreeNode(foundUiElement, optional, retryCount, longPress, offsetX, offsetY, device)
var currentRetry = 0
var hierarchy: TreeNode?
var hierarchyAfterTap: TreeNode?
do {
hierarchy =
hierarchySettleHelper.waitTillHierarchySettles(
config.loadingResourceIds,
device,
config.waitTillLoadingViewsGoneTimeout,
config.waitTillHierarchySettlesTimeout,
)

val foundUiElement =
findUiElementHelper.getUiElement(
uiElementIdentifier,
hierarchy,
optional,
device,
) ?: return

tapOnTreeNode(foundUiElement, longPress, offsetX, offsetY, device)

hierarchyAfterTap =
hierarchySettleHelper.waitTillHierarchySettles(
emptyList(),
device,
config.waitTillLoadingViewsGoneTimeout,
config.waitTillHierarchySettlesTimeout,
)
currentRetry++
} while (hierarchy == hierarchyAfterTap && currentRetry <= retryCount)

if (hierarchy == hierarchyAfterTap && !optional) {
throw IllegalStateException("Couldn't tap element $uiElementIdentifier")
}
}

private fun tapOnTreeNode(
uiElement: UiElement,
optional: Boolean,
retryCount: Int,
longPress: Boolean,
offsetX: Int,
offsetY: Int,
Expand All @@ -41,52 +64,16 @@ internal class TapHelper(
tap(
uiElement.x + (uiElement.width) / 2 + offsetX,
uiElement.y + (uiElement.height) / 2 + offsetY,
optional,
retryCount,
longPress,
device,
)
}

fun tap(
x: Int,
y: Int,
optional: Boolean,
retryCount: Int,
longPress: Boolean,
device: UiDevice,
) {
var currentTry = 1
while (currentTry <= retryCount) {
if (tap(x, y, longPress, device)) {
return
} else {
Thread.sleep(200)
currentTry++
}
}
if (!optional) {
throw IllegalStateException("Couldn't tap element at position: x:$x y:$y")
}
}

private fun tap(x: Int, y: Int, longPress: Boolean, device: UiDevice): Boolean {
val hierarchyBeforeTap = getHierarchyHelper.getHierarchy(device)

fun tap(x: Int, y: Int, longPress: Boolean, device: UiDevice) {
if (longPress) {
device.swipe(x, y, x, y, 200)
} else {
device.click(x, y)
}

val hierarchyAfterTap =
hierarchySettleHelper.waitTillHierarchySettles(
emptyList(),
device,
config.waitTillLoadingViewsGoneTimeout,
config.waitTillHierarchySettlesTimeout,
)

return hierarchyAfterTap != hierarchyBeforeTap
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,19 +66,19 @@ data class UiTestGlaze(
}

private val logger = Logger(config.logger)
private val printHierarchyHelper = PrintHierarchyHelper(logger)
private val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
private val getHierarchyHelper = GetHierarchyHelper(logger)
private val findUiElementHelper = FindUiElementHelper(logger, getHierarchyHelper)
private val assertionHelper = AssertionHelper(findUiElementHelper)
private val hierarchySettleHelper =
HierarchySettleHelper(getHierarchyHelper, findUiElementHelper, logger)
private val inputTextHelper =
InputTextHelper(getHierarchyHelper, findUiElementHelper)
private val printHierarchyHelper = PrintHierarchyHelper(logger)
InputTextHelper(config, getHierarchyHelper, findUiElementHelper, hierarchySettleHelper, printHierarchyHelper)
private val scrollHelper =
ScrollHelper(findUiElementHelper, getHierarchyHelper, hierarchySettleHelper)
private val tapHelper =
TapHelper(config, findUiElementHelper, hierarchySettleHelper, getHierarchyHelper)
TapHelper(config, findUiElementHelper, hierarchySettleHelper)

/**
* Tap on an element and expecting the UI to change.
Expand All @@ -96,39 +96,30 @@ data class UiTestGlaze(
offsetX: Int = 0,
offsetY: Int = 0,
) {
val hierarchy =
hierarchySettleHelper.waitTillHierarchySettles(
config.loadingResourceIds,
device,
config.waitTillLoadingViewsGoneTimeout,
config.waitTillHierarchySettlesTimeout,
)
tapHelper.tap(uiElementIdentifier, optional, retryCount, longPress, offsetX, offsetY, hierarchy, device)
tapHelper.tap(
uiElementIdentifier,
optional,
retryCount,
longPress,
offsetX,
offsetY,
device
)
}

/**
* Tap on a defined position and expecting the UI to change.
* Tap on a defined position.
*
* @param xPosition X position to tap.
* @param yPosition Y position to tap.
* @param optional If true, UiTestGlaze will not throw an exception if the element is not found.
* @param retryCount Number of times to retry if the Ui does not change after tapping.
* @param longPress If true, UiTestGlaze will long press on the element.
*/
fun tap(
xPosition: Int,
yPosition: Int,
optional: Boolean = false,
retryCount: Int = 3,
longPress: Boolean = false,
) {
hierarchySettleHelper.waitTillHierarchySettles(
config.loadingResourceIds,
device,
config.waitTillLoadingViewsGoneTimeout,
config.waitTillHierarchySettlesTimeout,
)
tapHelper.tap(xPosition, yPosition, optional, retryCount, longPress, device)
tapHelper.tap(xPosition, yPosition, longPress, device)
}

/**
Expand Down Expand Up @@ -215,11 +206,13 @@ data class UiTestGlaze(
* @param text Text to input.
* @param uiElementIdentifier Identifier of the element to input text.
* @param inputShouldBeRecognizedTimeout Timeout to wait till the input is recognized.
* @param numberOfRetries Number of times to retry if the input is not recognized.
*/
fun inputText(
text: String,
uiElementIdentifier: UiElementIdentifier,
inputShouldBeRecognizedTimeout: Duration = 3.seconds,
inputShouldBeRecognizedTimeout: Duration = 5.seconds,
numberOfRetries: Int = 3
) {
hierarchySettleHelper.waitTillHierarchySettles(
config.loadingResourceIds,
Expand All @@ -232,6 +225,7 @@ data class UiTestGlaze(
uiElementIdentifier = uiElementIdentifier,
device = device,
inputShouldBeRecognizedTimeout = inputShouldBeRecognizedTimeout,
numberOfRetries = numberOfRetries
)
}

Expand Down

0 comments on commit 6f85929

Please sign in to comment.