3

When I am opening the web app, I am getting a pop up. I'm trying to click on 'ALLOW' button in two ways:

1) When I add permissions:

caps.setCapability("autoGrantPermissions", true);
caps.setCapability("autoAcceptAlerts", true);
......
driver.switchTo().alert().accept();

nothing happens((

2) When I try to find it by XPath:

driver.findElement(By.xpath("//android.widget.Button[@text='Allow']")).click();

I get an error:

Exception in thread "main" org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"xpath","selector":"//android.widget.Button[@text='Allow']"}

This is my screenshot from UI Automator Viewer :

enter image description here

I found this post:Unable to tap the link after tap on Allow button of permission alert in Appium? but it didn't help me.

JohnPix
  • 978
  • 10
  • 27
  • could you please share the screenshot with UIAutomatorViewer by selecting the allow button. – Al Imran Jul 05 '18 at 02:22
  • @AlImran updated description, take a look please – JohnPix Jul 05 '18 at 06:12
  • have you tried `driver.findElement(By.id("android:id/button1")).click();` this one? – Al Imran Jul 06 '18 at 08:17
  • @AlImran it is not working, getting an error in logs: `Returned value cannot be converted to WebElement: {message=no such element: Unable to locate element: {"method":"id","selector":"android:id/button1"}` – JohnPix Jul 08 '18 at 09:37

3 Answers3

7

First: capabilities you were trying to use are for IOS only

On Android you have to find popup via findElement and close them yourself.

Second: since you start Appium session for web application, before searching for native popups you must switch the context:

    String webContext = driver.getContext();
    Set<String> contexts = driver.getContextHandles();
    for (String context: contexts){
        if (context.contains("NATIVE_APP")){
            driver.context(context);
            break;
        }
    }
    driver.findElement(By.id("android:id/button1")).click();

Don't forget to switch context back to web to continue:

    driver.context(webContext);
dmle
  • 3,056
  • 1
  • 10
  • 20
3

I had similar problem like yourself, here is how I solved this:

This is part of code from my page object where when clicking on useGPS, native Android notification is shown to allow or block GPS usage,

public Alert clickButtonUseGPSwithAlert() {
    buttonUseGps.click();
    Validate.action(getSessionInfo(), "click button 'Use a GPS'");
    Alert alert = new Alert(getSessionInfo());
    return alert;
}

and here is an overriden class Alert,

import io.appium.java_client.MobileElement;
import io.appium.java_client.pagefactory.AndroidFindBy;
import io.appium.java_client.pagefactory.AppiumFieldDecorator;
import io.appium.java_client.pagefactory.WithTimeout;
import org.openqa.selenium.support.PageFactory;
import pageObjects.Screen;
import utils.Validate;
import java.util.concurrent.TimeUnit;

public class Alert extends Screen implements org.openqa.selenium.Alert {
    @AndroidFindBy(id = "com.android.packageinstaller:id/dialog_container")
    @WithTimeout(time = 3, unit = TimeUnit.SECONDS)
    public MobileElement alertControl;

    @AndroidFindBy(id = "com.android.packageinstaller:id/permission_message")
    @WithTimeout(time = 3, unit = TimeUnit.SECONDS)
    private MobileElement content;

    @AndroidFindBy(id = "com.android.packageinstaller:id/permission_allow_button")
    @WithTimeout(time = 3, unit = TimeUnit.SECONDS)
    private MobileElement buttonAccept;

    @AndroidFindBy(id = "com.android.packageinstaller:id/permission_deny_button")
    @WithTimeout(time = 3, unit = TimeUnit.SECONDS)
    private MobileElement buttonDismiss;


    public Alert(SessionInfo sessionInfo){
        super(sessionInfo);
        PageFactory.initElements(new AppiumFieldDecorator(sessionInfo.getMobileDriver(), 3, TimeUnit.SECONDS), this);

        WaitUtils.isElementPresent(sessionInfo.getMobileDriver(),alertControl,2);

        if (!Util.areElementsLoaded(alertControl, content, buttonAccept, buttonDismiss)) {
            setLoaded(false);
        } else {
            setLoaded(true);
        }
        Validate.isScreenLoaded(getSessionInfo(), this.isLoaded());

    }

    @Override
    public void dismiss() {
        buttonDismiss.click();
        Validate.action(getSessionInfo(), "ALERT - click button 'Dismiss'");
    }

    @Override
    public void accept() {
        buttonAccept.click();
        Validate.action(getSessionInfo(), "ALERT - click button 'Accept'");
    }

    @Override
    public String getText() {
        String value = content.getText();
        Validate.action(getSessionInfo(), "ALERT - get content");
        return value;
    }

    @Override
    public void sendKeys(String s) {

    }
}

Ignore Screen extending, just try using implementation of existing Alert (org.openqa.selenium.Alert package).

I know this is not solution 1:1 You have to tweak it, to incorporate into Your code, but main point is to try to override Alert and wait for element to appear, and than interact with it.

Hope this would help You,

Kovacic
  • 1,427
  • 4
  • 21
1

Try to set the capabilities like this:

caps.setCapability("autoDismissAlerts", true);
caps.setCapability("autoGrantPermissions", true);
caps.setCapability("autoAcceptAlerts", true);
......
driver.switchTo().alert().accept();

If it won't help, try to find your 'ALLOW' button using this xPath:

//*[. = 'Allow']

or

//*[contains(text(), 'Allow')]

or

//*[contains(text(), 'ALLOW')]

or

driver.findElement(By.id("com.android.chrome:id/button1")).click();

Also you can try to locate this button by opening your app in a browser, then in dev tools locate the selector of this button and use it in Appium.

PS: add a WebDriverWait in your code:

new WebDriverWait(driver, 10).until(ExpectedConditions.elementToBeClickable(By.xpath("//*[. = 'Allow']"))).click();

This will wait at least 10 seconds until the element will be clickable. Sometimes the script is very quick and the DOM at that moment does not contain an element you want to interact with. So you have to wait some time until element will be in the DOM. That's why it is very useful to add wait in your script.

For the WebDriverWait you have to add some imports:

import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
Andrei Suvorkov
  • 5,191
  • 4
  • 17
  • 37