【问题标题】:Appium in Web app: Unable to tap Allow permission button in notification pop up windowWeb 应用程序中的 Appium:无法在通知弹出窗口中点击允许权限按钮
【发布时间】:2024-01-15 20:44:01
【问题描述】:

当我打开网络应用程序时,我会弹出一个窗口。我正在尝试以两种方式点击“允许”按钮:

1) 当我添加权限时:

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

什么都没发生((

2) 当我尝试通过 XPath 找到它时:

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

我收到一个错误:

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

这是我从 UI Automator Viewer 截屏:

我发现了这个帖子:Unable to tap the link after tap on Allow button of permission alert in Appium? 但这对我没有帮助。

【问题讨论】:

  • 您能否通过选择允许按钮将屏幕截图分享给 UIAutomatorViewer。
  • @AlImran 更新了描述,请看一下
  • 你试过driver.findElement(By.id("android:id/button1")).click();这个吗?
  • @AlImran 它不工作,日志中出现错误:Returned value cannot be converted to WebElement: {message=no such element: Unable to locate element: {"method":"id","selector":"android:id/button1"}

标签: java selenium testing automation appium


【解决方案1】:

首先:您尝试使用的功能适用于IOS only

在 Android 上,您必须通过 findElement 找到弹出窗口并自己关闭它们

第二:由于您为 Web 应用程序启动 Appium 会话,因此在搜索原生弹出窗口之前,您必须切换上下文

    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();

不要忘记将上下文切换回网络以继续:

    driver.context(webContext);

【讨论】:

  • 谢谢!它帮助了我
【解决方案2】:

我也遇到过类似的问题,我是这样解决的:

这是来自我的页面对象的代码的一部分,当点击 useGPS 时,会显示原生 Android 通知以允许或阻止 GPS 的使用,

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

这是一个被覆盖的类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) {

    }
}

忽略屏幕扩展,只需尝试使用现有 Alert 的实现(org.openqa.selenium.Alert 包)。

我知道这不是 1:1 的解决方案,您必须对其进行调整,将其合并到您的代码中,但重点是尝试覆盖 Alert 并等待元素出现,然后与之交互。

希望对你有帮助,

【讨论】:

    【解决方案3】:

    尝试像这样设置功能:

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

    如果没有帮助,请尝试使用此 xPath 找到您的“允许”按钮:

    //*[. = 'Allow']
    

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

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

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

    您也可以尝试通过在浏览器中打开您的应用来找到此按钮,然后在开发工具中找到此按钮的选择器并在 Appium 中使用它。

    PS:在您的代码中添加WebDriverWait

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

    这将等待至少 10 秒,直到元素可点击。有时脚本非常快,此时DOM 不包含您要与之交互的元素。因此,您必须等待一段时间,直到元素位于 DOM 中。这就是为什么在脚本中添加等待非常有用。

    对于WebDriverWait,您必须添加一些导入:

    import org.openqa.selenium.support.ui.ExpectedConditions;
    import org.openqa.selenium.support.ui.WebDriverWait;
    

    【讨论】: