Reputation: 4376
I want to test the permissions of Android 6, but I didn't find the way to click on the "Allow" button using Espresso. Is there a way to do this?
The version of Espresso is 2.2.1.
The test:
@Test
public void acceptFirstPermission() throws Exception {
onView(withText("ALLOW")).perform(click());
}
Behaviour:
I still receiving the frozen screen with the Dialog (like on the screenshot). Test executing all time until he becomes finished.
Output:
Running tests
Test running started
android.support.test.espresso.NoActivityResumedException: No activities in stage RESUMED. Did you forget to launch the activity. (test.getActivity() or similar)?
at dalvik.system.VMStack.getThreadStackTrace(Native Method)
at java.lang.Thread.getStackTrace(Thread.java:580)
at android.support.test.espresso.base.DefaultFailureHandler.getUserFriendlyError(DefaultFailureHandler.java:82)
at android.support.test.espresso.base.DefaultFailureHandler.handle(DefaultFailureHandler.java:53)
at android.support.test.espresso.ViewInteraction.runSynchronouslyOnUiThread(ViewInteraction.java:184)
at android.support.test.espresso.ViewInteraction.doPerform(ViewInteraction.java:115)
at android.support.test.espresso.ViewInteraction.perform(ViewInteraction.java:87)
at com.walletsaver.app.test.espresso.MarshmallowPermissionsTest.acceptFirstPermission(MarshmallowPermissionsTest.java:31)
at java.lang.reflect.Method.invoke(Native Method)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at android.support.test.internal.statement.UiThreadStatement.evaluate(UiThreadStatement.java:55)
at android.support.test.rule.ActivityTestRule$ActivityStatement.evaluate(ActivityTestRule.java:257)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at android.support.test.internal.runner.TestExecutor.execute(TestExecutor.java:54)
at android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:240)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1879)
Finish
Upvotes: 10
Views: 16914
Reputation: 1636
I've just hit the same problem, needing to dynamically allow or deny permissions but needed to be able to find the Button to click on the permissions dialog without using strings (as we'll be running in a range of other languages as well as English).
I had looked for a constant for the strings Allow and Deny that Android uses but couldn't find one, so went for the somewhat convoluted option of browsing the layout to find the layout with the app's name as shown in the permissions dialog (eg in this case "WalletSaver"), then go to parent layout of the dialog and then drill down to the other UI elements I want. NOTE: APP_NAME is just the user-visible string show in the popup dialog for your app name (since you control what the app is called and whether it's translated) - in this case "WalletSaver debug".
protected fun clickPermissionDeny() {
var dev = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
var deny : UiObject2
if (dev.findObjects(By.textContains(APP_NAME))[0].parent.parent.parent.children[1].childCount == 1) { // If there is no "don't ask again"
deny = dev.findObjects(By.textContains(APP_NAME))[0].parent.parent.parent.children[1].children[0].children[1].children[0]
} else { // Else move past checkbox
deny = dev.findObjects(By.textContains(APP_NAME))[0].parent.parent.parent.children[1].children[1].children[0].children[0]
}
deny.click();
}
protected fun clickPermissionAllow() {
var dev = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
var allow : UiObject2
while(dev.findObjects(By.textContains(APP_NAME))[0].parent.parent.parent.childCount<2)
Thread.sleep(100);
if (dev.findObjects(By.textContains(APP_NAME))[0].parent.parent.parent.children[1].childCount == 1) { // If there is no "don't ask again"
allow = dev.findObjects(By.textContains(APP_NAME))[0].parent.parent.parent.children[1].children[0].children[1].children[1]
} else { // Else move past checkbox
allow = dev.findObjects(By.textContains(APP_NAME))[0].parent.parent.parent.children[1].children[1].children[1].children[1]
}
allow.click()
}
While not exactly pretty, it'll do for the ui testing across a range of languages, hopefully.
EDITED: Updated to handle the case if user denies the request the first time (without a checkbox), the second time there's the checkbox present.
Upvotes: 0
Reputation: 613
If you use the UI-Automator with AndroidX, you can find the dialog and buttons.
It is a gradle dependency code.
dependencies {
androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0'
}
You can reach the ALLOW
button with this code.
It is Kotlin code.
val button = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
.findObject(
UiSelector().text(
activityTestRule
.activity
.getString(R.string.allow_button)
.toUpperCase()
)
)
if (button.exists() && button.isEnabled) {
button.click()
}
Upvotes: 0
Reputation: 11
You can use dynamic way to accept permissions if dialog appear permission will be granted if it not appear it will not throw any error
private static void allowPermissionsIfNeeded() {
if (Build.VERSION.SDK_INT >= 23) {
UiDevice device = UiDevice.getInstance(getInstrumentation());
UiObject allowPermissions = device.findObject(new UiSelector().text("ALLOW"));
if (allowPermissions.exists()) {
try {
allowPermissions.click();
} catch (UiObjectNotFoundException e) {
e.printStackTrace();
}
}
}
}
Upvotes: 1
Reputation: 24
The snippet below will grantPermissions before you run the tests. Hopefully it resolves your issue :)
@Before
public void grantPhonePermission() {
// In M+, trying to call a number will trigger a runtime dialog. Make sure
// the permission is granted before running this test.
// goo.gl/C8T4BU
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
getInstrumentation().getUiAutomation().executeShellCommand(
"pm grant " + getTargetContext().getPackageName()
+ " android.permission.READ_PHONE_STATE"
+ " android.permission.PHONE");
}
}
Upvotes: -3
Reputation: 40228
Well, it can be as simple as
onView(withText("Allow")).perform(click());
Of course this is not a perfect solution, so there are two ways to go to make it more robust: either analyze the app with hierarchyviewer to find hints on how to identify the button (e.g. content description), or dive into the Android source code for the tips (e.g. button's resource ID).
EDIT
Well, it's not that simple. I wrote an article about using UiAutomator to make this work.
Upvotes: 8
Reputation: 19351
I see that you're trying to test app permission. I think it might be pretty impossible to test it with Espresso. You may need to take this action another UI testing tool called uiatomator
.
uiatomator
, another great tools made by Google allows you to test your Android system functions like notifications and screen lock. You can use it with Espresso test framework.
For finding more info, please read this article:
http://qathread.blogspot.com/2015/05/espresso-uiautomator-perfect-tandem.html
and uiautomator documentation, which you would find here.
Upvotes: 10