diff --git a/.idea/androidTestResultsUserPreferences.xml b/.idea/androidTestResultsUserPreferences.xml new file mode 100644 index 0000000..6adf318 --- /dev/null +++ b/.idea/androidTestResultsUserPreferences.xml @@ -0,0 +1,191 @@ + + + + + + \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index b2cb255..888584a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,3 +10,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - `clickable` selector. +- `getObject` function works like `findObject` used to work (throws if the view represented by the UiObject doesn't exist). +- `findObject` now returns a `UiObject` even if the view represented by the UiObject doesn't exist. \ No newline at end of file diff --git a/relax/src/main/java/com/emergetools/relax/Flow.kt b/relax/src/main/java/com/emergetools/relax/Flow.kt index 46d2851..ca29c29 100644 --- a/relax/src/main/java/com/emergetools/relax/Flow.kt +++ b/relax/src/main/java/com/emergetools/relax/Flow.kt @@ -184,11 +184,19 @@ class Flow(val packageName: String, val config: FlowConfig) { textOrResId(textOrResId) } + /** + * @return A UiObject which represents a view that matches the criteria. + */ + fun findObject(select: RelaxSelector.() -> Unit): UiObject = intercept { + val selector = RelaxSelector(packageName).apply(select).toUiSelector() + device.findObject(selector) + } + /** * If the object exists, calls [block] on it and returns its return value, otherwise returns * [default]. */ - private fun findObject( + private fun getObject( select: RelaxSelector.() -> Unit, default: T, block: (UiObject) -> T @@ -197,12 +205,23 @@ class Flow(val packageName: String, val config: FlowConfig) { return if (obj.exists()) block(obj) else default } + /** + * @param textOrResId If the string contains ":id/" it will be treated as a resource ID, + * otherwise searches for the element whose visible text matches exactly. Matching is + * case-sensitive. + * @return A UiObject which represents a view that matches the criteria. + * @throws UiObjectNotFoundException if the view represented by this UiObject does not exist + */ + fun getObject(textOrResId: String) = getObject { + textOrResId(textOrResId) + } + /** * @return A UiObject which represents a view that matches the criteria. + * @throws UiObjectNotFoundException if the view represented by this UiObject does not exist */ - fun findObject(select: RelaxSelector.() -> Unit): UiObject = intercept { - val selector = RelaxSelector(packageName).apply(select).toUiSelector() - device.findObject(selector).also { + fun getObject(select: RelaxSelector.() -> Unit): UiObject = intercept { + findObject(select).also { if (!it.exists()) error(UiObjectNotFoundException(it.selector.toString())) } } @@ -233,7 +252,7 @@ class Flow(val packageName: String, val config: FlowConfig) { * @return true if successful, false otherwise */ fun click(select: RelaxSelector.() -> Unit): Boolean = intercept { - findObject(select, false) { + getObject(select, false) { it.click().also { result -> if (!result) error(UnsupportedOperationException("click ${it.selector}")) waitForIdle() @@ -281,7 +300,7 @@ class Flow(val packageName: String, val config: FlowConfig) { * @return true if successful, false otherwise */ fun longClick(select: RelaxSelector.() -> Unit): Boolean = intercept { - findObject(select, false) { + getObject(select, false) { it.longClick().also { result -> if (!result) error(UnsupportedOperationException("longClick ${it.selector}")) waitForIdle() @@ -322,7 +341,7 @@ class Flow(val packageName: String, val config: FlowConfig) { * @return true if successful, false otherwise */ fun inputText(inputText: String, select: RelaxSelector.() -> Unit): Boolean = intercept { - findObject(select, false) { + getObject(select, false) { it.setText(inputText).also { result -> if (!result) error(UnsupportedOperationException("inputText $inputText ${it.selector}")) waitForIdle() @@ -575,7 +594,7 @@ class Flow(val packageName: String, val config: FlowConfig) { * @return true if successful, false otherwise */ fun swipeDown(select: RelaxSelector.() -> Unit): Boolean = intercept { - findObject(select, false) { + getObject(select, false) { it.swipeDown(config.swipeSteps).also { result -> if (!result) error(UnsupportedOperationException("swipeDown ${it.selector}")) } @@ -608,7 +627,7 @@ class Flow(val packageName: String, val config: FlowConfig) { * @return true if successful, false otherwise */ fun swipeLeft(select: RelaxSelector.() -> Unit): Boolean = intercept { - findObject(select, false) { + getObject(select, false) { it.swipeLeft(config.swipeSteps).also { result -> if (!result) error(UnsupportedOperationException("swipeLeft ${it.selector}")) } @@ -641,7 +660,7 @@ class Flow(val packageName: String, val config: FlowConfig) { * @return true if successful, false otherwise */ fun swipeRight(select: RelaxSelector.() -> Unit): Boolean = intercept { - findObject(select, false) { + getObject(select, false) { it.swipeRight(config.swipeSteps).also { result -> if (!result) error(UnsupportedOperationException("swipeRight ${it.selector}")) } @@ -674,7 +693,7 @@ class Flow(val packageName: String, val config: FlowConfig) { * @return true if successful, false otherwise */ fun swipeUp(select: RelaxSelector.() -> Unit): Boolean = intercept { - findObject(select, false) { + getObject(select, false) { it.swipeUp(config.swipeSteps).also { result -> if (!result) error(UnsupportedOperationException("swipeUp ${it.selector}")) } diff --git a/tests/src/main/AndroidManifest.xml b/tests/src/main/AndroidManifest.xml index 3daa1c3..273da6a 100644 --- a/tests/src/main/AndroidManifest.xml +++ b/tests/src/main/AndroidManifest.xml @@ -3,5 +3,8 @@ + + + \ No newline at end of file diff --git a/tests/src/main/java/com/emergetools/relaxtests/AutoEmergeTest.kt b/tests/src/main/java/com/emergetools/relaxtests/AutoEmergeTest.kt new file mode 100644 index 0000000..2f034da --- /dev/null +++ b/tests/src/main/java/com/emergetools/relaxtests/AutoEmergeTest.kt @@ -0,0 +1,26 @@ +package com.emergetools.relaxtests + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.emergetools.relax.FlowConfig +import com.emergetools.relax.Relax +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class AutoEmergeTest { + + @Test + fun install() { + Relax("com.android.vending", FlowConfig(debug = true)) { + launchWithLink("https://play.google.com/store/apps/details?id=org.thoughtcrime.securesms") + + if (findObject { description("Open") }.exists()) return@Relax + + getObject { description("Install") }.click() + + val installing = findObject("Installing…") + installing.waitForExists(60_000) + installing.waitUntilGone(60_000) + } + } +} \ No newline at end of file diff --git a/tests/src/main/java/com/emergetools/relaxtests/FindObjectTest.kt b/tests/src/main/java/com/emergetools/relaxtests/FindObjectTest.kt index 58a81a3..bfbd91f 100644 --- a/tests/src/main/java/com/emergetools/relaxtests/FindObjectTest.kt +++ b/tests/src/main/java/com/emergetools/relaxtests/FindObjectTest.kt @@ -3,6 +3,7 @@ package com.emergetools.relaxtests import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.uiautomator.UiObjectNotFoundException import com.emergetools.relax.Relax +import org.junit.Assert.assertFalse import org.junit.Assert.assertThrows import org.junit.Assert.assertTrue import org.junit.Test @@ -12,7 +13,7 @@ import org.junit.runner.RunWith class FindObjectTest { @Test - fun findObject() { + fun findObjectExists() { Relax("com.emergetools.relaxexamples") { pressHome() launch() @@ -27,22 +28,9 @@ class FindObjectTest { Relax("com.emergetools.relaxexamples") { pressHome() launch() + val obj = findObject("DOESN'T EXIST") - assertThrows(UiObjectNotFoundException::class.java) { - findObject("DOESN'T EXIST") - } - } - } - - @Test - fun optionalFindObject() { - Relax("com.emergetools.relaxexamples") { - pressHome() - launch() - - optional { - findObject("DOESN'T EXIST") - } + assertFalse(obj.exists()) } } } diff --git a/tests/src/main/java/com/emergetools/relaxtests/GetObjectTest.kt b/tests/src/main/java/com/emergetools/relaxtests/GetObjectTest.kt new file mode 100644 index 0000000..1709ef6 --- /dev/null +++ b/tests/src/main/java/com/emergetools/relaxtests/GetObjectTest.kt @@ -0,0 +1,48 @@ +package com.emergetools.relaxtests + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.uiautomator.UiObjectNotFoundException +import com.emergetools.relax.Relax +import org.junit.Assert.assertThrows +import org.junit.Assert.assertTrue +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class GetObjectTest { + + @Test + fun getObject() { + Relax("com.emergetools.relaxexamples") { + pressHome() + launch() + val obj = getObject("NEXT") + + assertTrue(obj.exists()) + } + } + + @Test + fun getObjectDoesntExist() { + Relax("com.emergetools.relaxexamples") { + pressHome() + launch() + + assertThrows(UiObjectNotFoundException::class.java) { + getObject("DOESN'T EXIST") + } + } + } + + @Test + fun optionalGetObject() { + Relax("com.emergetools.relaxexamples") { + pressHome() + launch() + + optional { + getObject("DOESN'T EXIST") + } + } + } +}