用了 AppiumDriver 后,WebDriverWait 中无法使用 AppiumDriver 特有的方法

用了AppiumDriver后,WebDriverWait中无法使用AppiumDriver特有的方法,比如findElementsByAndroidUIAutomator等。这是由于
WebDriverWait继承与FluentWait<WebDriver>,而WebDriver接口是没有定义findElementsByAndroidUIAutomator的,所以如果想用类似WebDriverWait的功能,就必须做些封装。

package com.merlini.app.common;

import io.appium.java_client.AppiumDriver;

import java.util.concurrent.TimeUnit;

import org.openqa.selenium.NotFoundException;
import org.openqa.selenium.support.ui.Clock;
import org.openqa.selenium.support.ui.FluentWait;
import org.openqa.selenium.support.ui.Sleeper;
import org.openqa.selenium.support.ui.SystemClock;
import org.openqa.selenium.support.ui.WebDriverWait;

import com.merlini.common.Config;


public class AppiumDriverWait extends FluentWait<AppiumDriver>{
    //默认轮询时间(毫秒)
    public final static long DEFAULT_POLLINGEVERY_TIMEMILLS = Integer.parseInt(Config.getConfBykey("wait.sleepInMillis"));
    public final static long DEFAULT_TIMEOUT_INSECONDS = Integer.parseInt(Config.getConfBykey("wait.TimeOutInSeconds"));
    /**
       * Wait will ignore instances of NotFoundException that are encountered (thrown) by default in
       * the 'until' condition, and immediately propagate all others.  You can add more to the ignore
       * list by calling ignoring(exceptions to add).
       *
       * @param driver The AppiumDriver instance to pass to the expected conditions
       * @see WebDriverWait#ignoring(java.lang.Class)
       */
    public AppiumDriverWait(AppiumDriver driver) {
        this(driver, new SystemClock(), Sleeper.SYSTEM_SLEEPER, DEFAULT_TIMEOUT_INSECONDS, DEFAULT_POLLINGEVERY_TIMEMILLS);
    }
    /**
       * Wait will ignore instances of NotFoundException that are encountered (thrown) by default in
       * the 'until' condition, and immediately propagate all others.  You can add more to the ignore
       * list by calling ignoring(exceptions to add).
       *
       * @param driver The AppiumDriver instance to pass to the expected conditions
       * @param timeOutInSeconds The timeout in seconds when an expectation is called
       * @see WebDriverWait#ignoring(java.lang.Class)
       */
    public AppiumDriverWait(AppiumDriver driver, long timeOutInSeconds) {
        this(driver, new SystemClock(), Sleeper.SYSTEM_SLEEPER, timeOutInSeconds, DEFAULT_POLLINGEVERY_TIMEMILLS);
    }
    /**
       * Wait will ignore instances of NotFoundException that are encountered (thrown) by default in
       * the 'until' condition, and immediately propagate all others.  You can add more to the ignore
       * list by calling ignoring(exceptions to add).
       *
       * @param driver The WebDriver instance to pass to the expected conditions
       * @param timeOutInSeconds The timeout in seconds when an expectation is called
       * @param sleepInMillis The duration in milliseconds to sleep between polls.
       * @see WebDriverWait#ignoring(java.lang.Class)
       */
    public AppiumDriverWait(AppiumDriver driver, long timeOutInSeconds, long sleepInMillis) {
        this(driver, new SystemClock(), Sleeper.SYSTEM_SLEEPER, timeOutInSeconds, sleepInMillis);
      }
    protected AppiumDriverWait(AppiumDriver driver, Clock clock, Sleeper sleeper, long timeOutInSeconds,
          long sleepTimeOut) {
        super(driver, clock, sleeper);
        withTimeout(timeOutInSeconds, TimeUnit.SECONDS);
        pollingEvery(sleepTimeOut, TimeUnit.MILLISECONDS);
        ignoring(NotFoundException.class);
    }


}


package com.merlini.app.common;

import io.appium.java_client.AppiumDriver;

import com.google.common.base.Function;

public interface AppiumExpectedCondition<T> extends Function<AppiumDriver,T>{

}

这样就可以 AppiumDriverWait 代替WebDriverWait
如:

/**
     * 根据控件description抓取批量元素
     * @param elementType
     * @param desc
     * @return
     */
    public List<WebElement> findElementsByDescription(final String elementType,final String desc){
        AppiumDriverWait wait=new AppiumDriverWait(driver);
        List<WebElement> ele= wait.until( new AppiumExpectedCondition<List<WebElement>>(){
            public List<WebElement> apply(AppiumDriver driver){
                return driver.findElementsByAndroidUIAutomator("new UiSelector().className(\"android.widget."+elementType+"\").description(\""+desc+"\")");
            }
        });
        return ele;//driver.findElementsByAndroidUIAutomator("new UiSelector().className(\"android.widget."+elementType+"\").description(\""+desc+"\")"); 
    }
本帖已被设为精华帖!
共收到 8 条回复
1楼 已删除.
155

apply中使用By可能可以解决,不要直接使用WebDriver/AppiumDriver

1185
kuroky 3楼 · 5月前 1 人喜欢

没有By.AndroidUIAutomator的,难道BY有针对AppiumDriver的封装?

403574cd2a42e73c9f34b2b14e2bf9b4
qddegtya 4楼 · 5月前 喜欢

#3楼 @kuroky

之前我在源码剖析帖里就有提及
mobileby类扩展了之前的By类。

#!/usr/bin/env python

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from selenium.webdriver.common.by import By


class MobileBy(By):
    IOS_UIAUTOMATION = '-ios uiautomation'
    ANDROID_UIAUTOMATOR = '-android uiautomator'
    ACCESSIBILITY_ID = 'accessibility id'
1185
kuroky 5楼 · 5月前 喜欢

试试看这个靠不靠普 ,啥时候加到加到接口里面就好了 ,还有那个mobileElement 用起来相当不便

403574cd2a42e73c9f34b2b14e2bf9b4
qddegtya 6楼 · 5月前 喜欢

#5楼 @kuroky

拿expected_conditions中的presence_of_element_located举例来说
webdriver.support中的expected_conditions中定义的该可调用类中直接调用的就是核心的find_element方法
而AppiumDriver定义的那些Find方法调用的正是这个核心方法,只不过他扩展了By类,所以,这边是可以通过访问MobileBy的相关属性来实现smartwait的

class presence_of_all_elements_located(object):
    """ An expectation for checking that there is at least one element present
    on a web page.
    locator is used to find the element
    returns the list of WebElements once they are located
    """
    def __init__(self, locator):
        self.locator = locator

    def __call__(self, driver):
        return _find_elements(driver, self.locator)
def _find_elements(driver, by):
    try :
        return driver.find_elements(*by)
    except WebDriverException as e:
        raise e
155
532589730 7楼 · 5月前 喜欢

#3楼 @kuroky
有,MobileBy方法返回的就是By,可以把appiumdriver封装的accessibilityid方法拆出来。
java MobileBy源码:

package io.appium.java_client;

import org.openqa.selenium.By;
import org.openqa.selenium.SearchContext;
import org.openqa.selenium.WebElement;

import java.io.Serializable;
import java.util.List;

/**
 * Created by jonahss on 4/10/14.
 */
public abstract class MobileBy extends By {

  public static By IosUIAutomation(final String uiautomationText) {
    if (uiautomationText == null) {
      throw new IllegalArgumentException("Must supply an iOS UIAutomation string");
    }

    return new ByIosUIAutomation(uiautomationText);
  }

  public static By AndroidUIAutomator(final String uiautomatorText) {
    if (uiautomatorText == null) {
      throw new IllegalArgumentException("Must supply an Android UIAutomator string");
    }

    return new ByAndroidUIAutomator(uiautomatorText);
  }

  public static By AccessibilityId(final String id) {
    if (id == null) {
      throw new IllegalArgumentException("Must supply a uiautomationText");
    }

    return new ByAccessibilityId(id);
  }

  public static class ByIosUIAutomation extends By implements Serializable {

    private final String automationText;

    public ByIosUIAutomation(String uiautomationText)   {
      automationText = uiautomationText;
    }

    @Override
    public List<WebElement> findElements(SearchContext context) {
      return ((FindsByIosUIAutomation) context).findElementsByIosUIAutomation(automationText);
    }

    @Override
    public WebElement findElement(SearchContext context) {
      return ((FindsByIosUIAutomation) context).findElementByIosUIAutomation(automationText);
    }

    @Override
    public String toString() {
      return "By.IosUIAutomation: " + automationText;
    }
  }

  public static class ByAndroidUIAutomator extends By implements Serializable {

    private final String automatorText;

    public ByAndroidUIAutomator(String uiautomatorText) {
      automatorText = uiautomatorText;
    }

    @Override
    public List<WebElement> findElements(SearchContext context) {
      return ((FindsByAndroidUIAutomator) context).findElementsByAndroidUIAutomator(automatorText);
    }

    @Override
    public WebElement findElement(SearchContext context) {
      return ((FindsByAndroidUIAutomator) context).findElementByAndroidUIAutomator(automatorText);
    }

    @Override
    public String toString() { return "By.AndroidUIAutomator: " + automatorText; }
  }

  public static class ByAccessibilityId extends By implements Serializable {

    private final String id;

    public ByAccessibilityId(String id)   {
      this.id = id;
    }

    @Override
    public List<WebElement> findElements(SearchContext context) {
      return ((FindsByAccessibilityId) context).findElementsByAccessibilityId(id);
    }

    @Override
    public WebElement findElement(SearchContext context) {
      return ((FindsByAccessibilityId) context).findElementByAccessibilityId(id);
    }

    @Override
    public String toString() {
      return "By.AccessibilityId: " + id;
    }
  }
}



6eefc951ce355f3a056acf1c45a41a96

Config.getConfBykey("wait.sleepInMillis");
这是个什么东西啊?我的编译器不认识Config.getConfBykey这个东东

1185
kuroky 9楼 · 5月前 喜欢

#8楼 @shimazakiharuka 这个是配置信息,是个是数字

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值