Espresso - click on the button of the dialog
Asked Answered
L

6

10

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?

enter image description here

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
Lucero answered 23/12, 2015 at 15:39 Comment(1)
Possible duplicate of Android Marshmallow: Test permissions with Espresso?Pyrene
A
10

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.

Amateur answered 23/12, 2015 at 16:55 Comment(1)
UI Automator works perfectly with permission's dialog. Thanks!Lucero
K
8

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.

Karlie answered 23/12, 2015 at 15:56 Comment(5)
Unfortunately, it does not work. I still receiving the frozen screen with the dialog (like on the screenshot in the question). Test executing all time until he becomes finished.Lucero
Could you please update your question with the code of your test? Normally if the test hadn't found the button by text it would've failed.Karlie
Are you actually forgetting to call getActivity(), as the test result suggests?Karlie
Actually, Activity is visible and waiting for the action. I can't get how you suggest to call the test.getActivity(). Can you update your answer with the sample of code, please?Lucero
espresso wont interact with alerts, only the app itselfAbreast
S
1

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();
                }
            }
        }
    }
Simmons answered 15/4, 2019 at 12:6 Comment(0)
I
0

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()
}
Inflatable answered 26/9, 2019 at 14:54 Comment(0)
P
0

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.

Pamella answered 5/11, 2019 at 15:15 Comment(0)
S
-3

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");
        }
    }
Saunderson answered 11/10, 2016 at 22:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.