zoukankan      html  css  js  c++  java
  • appium():PageObject&PageFactory

    Appium Java client has facilities which components to Page Object design pattern and Selenium PageFactory.//appium的java客户端支持PageObject和PageFactory。读本文之前一定要有PageObject和PageFactory的概念。

    原文地址:https://github.com/appium/java-client/blob/master/docs/Page-objects.md#specification

    //第一部分:讲解声明filed时,如何使用注解

    WebElement/list of WebElement field can be populated by default:

    //对于WebElement使用@Findby注解,元素类型是WebElement。
     1 import org.openqa.selenium.WebElement;
     2 import org.openqa.selenium.support.FindBy;
     3 ...
     4 
     5 @FindBy(someStrategy) //for browser or web view html UI 
     6 //also for mobile native applications when other locator strategies are not defined
     7 WebElement someElement;
     8 
     9 @FindBy(someStrategy) //for browser or web view html UI 
    10 //also for mobile native applications when other locator strategies are not defined
    11 List<WebElement> someElements;
    
    

    If there is need to use convinient locators for mobile native applications then the following is available:

    //对于移动端原生应用,分别使用@AndroidFindBy@SelendroidFindBy@iOSFindBy注解,元素类型分别为AndroidElement、RemoteWebElement、IOSElement。

     1 import io.appium.java_client.android.AndroidElement;
     2 import org.openqa.selenium.remote.RemoteWebElement;
     3 import io.appium.java_client.pagefactory.*;
     4 import io.appium.java_client.ios.IOSElement;
     5 
     6 @AndroidFindBy(someStrategy) //for Android UI when Android UI automator is used
     7 AndroidElement someElement;
     8 
     9 @AndroidFindBy(someStrategy) //for Android UI when Android UI automator is used
    10 List<AndroidElement> someElements;
    11 
    12 @SelendroidFindBy(someStrategy) //for Android UI when Selendroid automation is used
    13 RemoteWebElement someElement;
    14 
    15 @SelendroidFindBy(someStrategy) //for Android UI when Selendroid automation is used
    16 List<RemoteWebElement> someElements;
    17 
    18 @iOSFindBy(someStrategy) //for iOS native UI
    19 IOSElement someElement;
    20 
    21 @iOSFindBy(someStrategy) //for iOS native UI
    22 List<IOSElement> someElements;

    The example for the crossplatform mobile native testing

    //跨平台时,同时使用@AndroidFindBy@iOSFindBy注解,元素类型为MobileElement。

     1 import io.appium.java_client.MobileElement;
     2 import io.appium.java_client.pagefactory.*;
     3 
     4 @AndroidFindBy(someStrategy) 
     5 @iOSFindBy(someStrategy) 
     6 MobileElement someElement;
     7 
     8 @AndroidFindBy(someStrategy) //for the crossplatform mobile native
     9 @iOSFindBy(someStrategy) //testing
    10 List<MobileElement> someElements;

    The fully cross platform examle

    //全平台时,同时使用@FindBy@AndroidFindBy@iOSFindBy注解,元素类型为RemoteWebElement。

     1 import org.openqa.selenium.remote.RemoteWebElement;
     2 import io.appium.java_client.pagefactory.*;
     3 import org.openqa.selenium.support.FindBy;
     4 
     5 //the fully cross platform examle
     6 @FindBy(someStrategy) //for browser or web view html UI
     7 @AndroidFindBy(someStrategy) //for Android native UI 
     8 @iOSFindBy(someStrategy)  //for iOS native UI 
     9 RemoteWebElement someElement;
    10 
    11 //the fully cross platform examle
    12 @FindBy(someStrategy)
    13 @AndroidFindBy(someStrategy) //for Android native UI 
    14 @iOSFindBy(someStrategy)  //for iOS native UI 
    15 List<RemoteWebElement> someElements;

    Also it is possible to define chained or any possible locators.

    //chained是指使用@FindBys、@AndroidFindBys、@iOSFindBys注解。修饰列表变量时,列表的内容是多个定位方法找到的元素。修饰非列表变量时,变量值是什么呢?

    - Chained

    If you use build versions < 5.x.x

     1 import org.openqa.selenium.remote.RemoteWebElement;
     2 import io.appium.java_client.pagefactory.*;
     3 import org.openqa.selenium.support.FindBys;
     4 import org.openqa.selenium.support.FindBy;
     5 
     6 @FindBys({@FindBy(someStrategy1), @FindBy(someStrategy2)}) 
     7 @AndroidFindBys({@AndroidFindBy(someStrategy1), @AndroidFindBy(someStrategy2)}) 
     8 @iOSFindBys({@iOSFindBy(someStrategy1), @iOSFindBy(someStrategy2)}) 
     9 RemoteWebElement someElement;
    10 
    11 @FindBys({@FindBy(someStrategy1), @FindBy(someStrategy2)}) 
    12 @AndroidFindBys({@AndroidFindBy(someStrategy1), @AndroidFindBy(someStrategy2)}) 
    13 @iOSFindBys({@iOSFindBy(someStrategy1), @iOSFindBy(someStrategy2)}) 
    14 List<RemoteWebElement> someElements;

    If you use build versions >= 5.x.x

     1 import org.openqa.selenium.remote.RemoteWebElement;
     2 import io.appium.java_client.pagefactory.*;
     3 import org.openqa.selenium.support.FindBys;
     4 import org.openqa.selenium.support.FindBy;
     5 
     6 @FindBys({@FindBy(someStrategy1), @FindBy(someStrategy2)}) 
     7 @AndroidFindBy(someStrategy1) @AndroidFindBy(someStrategy2)
     8 @iOSFindBy(someStrategy1) @iOSFindBy(someStrategy2) 
     9 RemoteWebElement someElement;
    10 
    11 @FindBys({@FindBy(someStrategy1), @FindBy(someStrategy2)}) 
    12 @AndroidFindBy(someStrategy1) @AndroidFindBy(someStrategy2)
    13 @iOSFindBy(someStrategy1) @iOSFindBy(someStrategy2)
    14 List<RemoteWebElement> someElements;

    or

     1 import org.openqa.selenium.remote.RemoteWebElement;
     2 import io.appium.java_client.pagefactory.*;
     3 import org.openqa.selenium.support.FindBys;
     4 import org.openqa.selenium.support.FindBy;
     5 
     6 import static io.appium.java_client.pagefactory.LocatorGroupStrategy.CHAIN;
     7 
     8 @HowToUseLocators(androidAutomation = CHAIN, iOSAutomation = CHAIN)
     9 @FindBys({@FindBy(someStrategy1), @FindBy(someStrategy2)}) 
    10 @AndroidFindBy(someStrategy1) @AndroidFindBy(someStrategy2)
    11 @iOSFindBy(someStrategy1) @iOSFindBy(someStrategy2) 
    12 RemoteWebElement someElement;
    13 
    14 @HowToUseLocators(androidAutomation = CHAIN, iOSAutomation = CHAIN)
    15 @FindBys({@FindBy(someStrategy1), @FindBy(someStrategy2)}) 
    16 @AndroidFindBy(someStrategy1) @AndroidFindBy(someStrategy2)
    17 @iOSFindBy(someStrategy1) @iOSFindBy(someStrategy2)
    18 List<RemoteWebElement> someElements;

    //possible是指使用@FindAll@AndroidFindAll@iOSFindAll注解。如果修饰列表变量,那么列表的内容是由全部声明的定位方法找到的元素。如果修饰非列表变量,那么变量值是第一个被找到的元素,无论是使用哪个已声明的定位方法。

    - Any possible

    If you use build versions < 5.x.x

     1 import org.openqa.selenium.remote.RemoteWebElement;
     2 import io.appium.java_client.pagefactory.*;
     3 import org.openqa.selenium.support.FindBy;
     4 import org.openqa.selenium.support.FindByAll;
     5 
     6 @FindAll({@FindBy(someStrategy1), @FindBy(someStrategy2)}) 
     7 @AndroidFindAll({@AndroidFindBy(someStrategy1), @AndroidFindBy(someStrategy2)}) 
     8 @iOSFindAll({@iOSFindBy(someStrategy1), @iOSFindBy(someStrategy2)}) 
     9 RemoteWebElement someElement;
    10 
    11 @FindAll({@FindBy(someStrategy1), @FindBy(someStrategy2)}) 
    12 @AndroidFindAll({@AndroidFindBy(someStrategy1), @AndroidFindBy(someStrategy2)}) 
    13 @iOSFindAll({@iOSFindBy(someStrategy1), @iOSFindBy(someStrategy2)}) 
    14 List<RemoteWebElement> someElements;

    If you use build versions >= 5.x.x

     1 import org.openqa.selenium.remote.RemoteWebElement;
     2 import io.appium.java_client.pagefactory.*;
     3 import org.openqa.selenium.support.FindBy;
     4 import org.openqa.selenium.support.FindByAll;
     5 
     6 import static io.appium.java_client.pagefactory.LocatorGroupStrategy.ALL_POSSIBLE;
     7 
     8 @HowToUseLocators(androidAutomation = ALL_POSSIBLE, iOSAutomation = ALL_POSSIBLE)
     9 @FindAll{@FindBy(someStrategy1), @FindBy(someStrategy2)}) 
    10 @AndroidFindBy(someStrategy1) @AndroidFindBy(someStrategy2) 
    11 @iOSFindBy(someStrategy1) @iOSFindBy(someStrategy2) 
    12 RemoteWebElement someElement;
    13 
    14 @HowToUseLocators(androidAutomation = ALL_POSSIBLE, iOSAutomation = ALL_POSSIBLE)
    15 @FindAll({@FindBy(someStrategy1), @FindBy(someStrategy2)}) 
    16 @AndroidFindBy(someStrategy1) @AndroidFindBy(someStrategy2)
    17 @iOSFindBy(someStrategy1) @iOSFindBy(someStrategy2)
    18 List<RemoteWebElement> someElements;

    Also possible combined variants:

     1 import org.openqa.selenium.remote.RemoteWebElement;
     2 import io.appium.java_client.pagefactory.*;
     3 import org.openqa.selenium.support.FindBy;
     4 import org.openqa.selenium.support.FindByAll;
     5 
     6 import static io.appium.java_client.pagefactory.LocatorGroupStrategy.CHAIN;
     7 import static io.appium.java_client.pagefactory.LocatorGroupStrategy.ALL_POSSIBLE;
     8 
     9 @HowToUseLocators(androidAutomation = CHAIN, iOSAutomation = ALL_POSSIBLE)
    10 @FindAll{@FindBy(someStrategy1), @FindBy(someStrategy2)}) 
    11 @AndroidFindBy(someStrategy1) @AndroidFindBy(someStrategy2) 
    12 @iOSFindBy(someStrategy1) @iOSFindBy(someStrategy2) 
    13 RemoteWebElement someElement;
    14 
    15 @HowToUseLocators(androidAutomation = CHAIN, iOSAutomation = ALL_POSSIBLE)
    16 @FindAll({@FindBy(someStrategy1), @FindBy(someStrategy2)}) 
    17 @AndroidFindBy(someStrategy1) @AndroidFindBy(someStrategy2)
    18 @iOSFindBy(someStrategy1) @iOSFindBy(someStrategy2)
    19 List<RemoteWebElement> someElements;

    or

     1 import org.openqa.selenium.remote.RemoteWebElement;
     2 import io.appium.java_client.pagefactory.*;
     3 import org.openqa.selenium.support.FindBy;
     4 import org.openqa.selenium.support.FindByAll;
     5 
     6 import static io.appium.java_client.pagefactory.LocatorGroupStrategy.ALL_POSSIBLE;
     7 
     8 @HowToUseLocators(iOSAutomation = ALL_POSSIBLE)
     9 @FindAll{@FindBy(someStrategy1), @FindBy(someStrategy2)}) 
    10 @AndroidFindBy(someStrategy1) @AndroidFindBy(someStrategy2) //this is the chain 
    11 //by default
    12 @iOSFindBy(someStrategy1) @iOSFindBy(someStrategy2) 
    13 RemoteWebElement someElement;
    14 
    15 @HowToUseLocators(iOSAutomation = ALL_POSSIBLE)
    16 @FindAll({@FindBy(someStrategy1), @FindBy(someStrategy2)}) 
    17 @AndroidFindBy(someStrategy1) @AndroidFindBy(someStrategy2) //this is the chain 
    18 //by default
    19 @iOSFindBy(someStrategy1) @iOSFindBy(someStrategy2)
    20 List<RemoteWebElement> someElements;

    //第二部分:讲解如何使用PageFactory初始化field。

    Appium Java client is integrated with Selenium PageFactory by AppiumFieldDecorator.

    Object fields are populated as below://按照这个方式初始化。

    1 import io.appium.java_client.pagefactory.*;
    2 import org.openqa.selenium.support.PageFactory;
    3 
    4 PageFactory.initElements(new AppiumFieldDecorator(searchContext 
    5               /*searchContext is a WebDriver or WebElement
    6               instance */), 
    7               pageObject //an instance of PageObject.class
    8 );

     //初始化时,可以设置元素定位的超时时间。

     1 import io.appium.java_client.pagefactory.*;
     2 import org.openqa.selenium.support.PageFactory;
     3 import java.util.concurrent.TimeUnit;
     4 
     5 PageFactory.initElements(new AppiumFieldDecorator(searchContext, 
     6               /*searchContext is a WebDriver or WebElement
     7               instance */
     8         15, //default implicit waiting timeout for all strategies//效果为:至少用15个时间单位查找元素。
     9         TimeUnit.SECONDS), 
    10             pageObject //an instance of PageObject.class
    11 );
    12 import io.appium.java_client.pagefactory.*;
    13 import org.openqa.selenium.support.PageFactory;
    14 import java.util.concurrent.TimeUnit;
    15 
    16 PageFactory.initElements(new AppiumFieldDecorator(searchContext, 
    17               /*searchContext is a WebDriver or WebElement
    18               instance */
    19         new TimeOutDuration(15, //default implicit waiting timeout for all strategies
    20         TimeUnit.SECONDS)), //效果为:至少用15个时间单位查找元素。
    
    
    21 pageObject //an instance of PageObject.class 22 );

    If time of the waiting for elements differs from usual (longer, or shorter when element is needed only for quick checkings/assertions) then//还可以为每个元素单独设置超时时间。

    1 import io.appium.java_client.pagefactory.*;
    2 
    3 @WithTimeout(timeOut = yourTime, timeUnit = yourTimeUnit)
    4 RemoteWebElement someElement;
    5 
    6 @WithTimeout(timeOut = yourTime, timeUnit = yourTimeUnit)
    7 List<RemoteWebElement> someElements;

    //第三部分:讲解一个例子。

    The additional feature.

    The simple example

    Let's imagine that the task is to check an Android client of the http://www.rottentomatoes.com. Let it be like a picture below

     

    Lets imagine that it is only a part of the screen.

    A typical page object could look like://典型的page object的写法

     1 public class RottenTomatoesScreen {
     2     //convinient locator  
     3     private List<AndroidElement> titles;
     4 
     5     //convinient locator  
     6     private List<AndroidElement> scores;
     7 
     8     //convinient locator  
     9     private List<AndroidElement> castings;
    10     //element declaration goes on 
    11 
    12     public String getMovieCount(){
    13        //.......
    14     }  
    15 
    16     public String getTitle(params){
    17        //.......
    18     }  
    19 
    20     public String getScore(params){
    21       //.......
    22     }  
    23 
    24     public String getCasting(params){
    25       //.......
    26     } 
    27 
    28     public void openMovieInfo(params){
    29       //.......
    30     } 
    31 
    32     //method declaration goes on 
    33 }

    The description above can be decomposed. Let's work it out!//上面的PageObject写法,可以进行拆解。

    Firstly a Movie-widget could be described this way://首先,定义一个widget:猜测是页面上的一个对象,假设烂番茄网站上也有电视剧、动画片的信息,而这两者又有不同的介绍,比如电视剧有演员信息,动画片有配音人员和设计师的信息,那么电视剧和动画可以看做是两个不同的widget。

     1 import io.appium.java_client.pagefactory.Widget;
     2 import org.openqa.selenium.WebElement;
     3 
     4 public class Movie extends Widget{
     5    protected Movie(WebElement element) {
     6         super(element);
     7    }
     8 
     9    //convinient locator  //大多时候,不同movie的具有相同的id或者classname,这时候用id或者classname就可以定位全部的movie。同理,不同movie的title也都有相同的id或者classname,一个定位字符串可以通用与全部的title。
    10    private AndroidElement title;
    11 
    12    //convinient locator  
    13    private AndroidElement score;
    14 
    15    //convinient locator  
    16    private AndroidElement casting;
    17 
    18    public String getTitle(params){
    19        //.......
    20    }  
    21 
    22    public String getScore(params){
    23       //.......
    24    }  
    25 
    26    public String getCasting(params){
    27       //.......
    28    } 
    29 
    30    public void openMovieInfo(params){
    31        ((AndroidElement) getWrappedElement()).tap(1, 1500);
    32    } 
    33 
    34 }

    So, now page object looks

     1 public class RottenTomatoesScreen {
     2 
     3      @AndroidFindBy(a locator which convinient to find a single movie-root - element)//不同movie具有相同的id或者classname,这时候一个定位字符串可以通用于全部的movie。
     4      private List<Movie> movies;
     5 
     6       //element declaration goes on 
     7 
     8      public String getMovieCount(){
     9         return movies.size();
    10      }  
    11 
    12      public Movie getMovie(int index){
    13         //any interaction with sub-elements of a movie-element
    14         //will be performed outside of the page-object instance 
    15         return movie.get(index);
    16      }
    17      //method declaration goes on 
    18 }

    Ok. What if Movie-class is reused and a wrapped root element is usually found by the same locator?

    Then//如果需要使用movie类生成多个实例,而且这些实例使用同一个定位字符串,那么可以将实例的注解移到定义movie类的代码前面。

    1 //the class is annotated !!!
    2 @AndroidFindBy(a locator which convinient to find a single movie-root - element)
    3 public class Movie extends Widget{
    4 ...
    5 }

    and

    1 public class RottenTomatoesScreen {
    2      //!!! locator is not necessary at this case
    3      private List<Movie> movies;
    4 ...
    5 }

    Ok. What if movie list is not a whole screen? E.g. we want to describe it as a widget with nested movies.

    Then://这里是说,如何生成一个特殊的widget,它的内部元素还是widget。假设当前页面是一个内容非常丰富的页面,有电影、电视剧、综艺节目相关的信息,电影分类内部的每个电影都有名字、得分、剧情简介等信息,电视剧和综艺节目也有各自的内部信息。此时,每部电影都是一个小的widget,电影类别则是一个大的widget,整个页面由电影、电视剧、综艺节目三个大的widget组成。注解的使用方法同前面一样。

    1 //with the usual locator or without it
    2 public class Movies extends Widget{
    3 
    4     //with a custom locator or without it
    5     private List<Movie> movies;
    6 ...
    7 }

    and

    1 public class RottenTomatoesScreen {
    2 
    3     //with a custom locator or without it
    4     Movies movies;
    5 ...
    6 }

    Good! How to poputate all these fields?

    As usual:

    1 RottenTomatoesScreen screen = new RottenTomatoesScreen();
    2 PageFactory.initElements(new AppiumFieldDecorator(searchContext /*WebDriver or WebElement
    3               instance */), screen);

    //第四部分:说明

    Specification

    A class which describes a widget or group of elements should extend//要想使用widget,必须要继承widget类。

    io.appium.java_client.pagefactory.Widget;

    Any widget/group of elements can be described it terms of sub-elements or nested sub-widgets.
    Appium-specific annotations are used for this purpose.

    Any class which describes the real widget or group of elements can be annotated

    That means that when the same "widget" is used frequently and any root element of this can be found by the same locator then user can

     1 @FindBy(relevant locator) //how to find a root element//假设UsersWidget对应于实际页面的movie,那么这个定位字符串是能够匹配全部movie的通用的字符串。
     2 public class UsersWidget extends Widget{
     3 
     4   @FindBy(relevant locator) //this element will be found //同理,这里的定位字符串也必须是通用的匹配全部subElement1的字符串。
     5   //using the root element
     6   WebElement subElement1;
     7 
     8   @FindBy(relevant locator) //this element will be found 
     9   //using the root element
    10   WebElement subElement2;
    11 
    12   @FindBy(relevant locator) //a root element 
    13   //of this widget is the sub-element which 
    14   //will be found from top-element
    15   UsersWidget subWidget;
    16 
    17   //and so on..   
    18 }

    and then it is enough

    1   //above is the other field declaration
    2 
    3   UsersWidget widget;
    4 
    5   //below is the other field/method declaration

    If the widget really should be found using an another locator then

    1   //above is the other field declaration
    2   @FindBy(another relevant locator) //this locator overrides //这里的定位字符串可以覆盖声明类时使用的定位字符串。
    3   //the declared in the using class
    4   UsersWidget widget;
    5 
    6   //below is the other field/method declaration

    Ok. What should users do if they want to implement a subclass which describes a similar group of elements for the same platform?

    There is nothing special.//子类继承父类没有特殊的操作。

    1 @FindBy(relevant locator) //how to find a root element
    2 public class UsersWidget extends Widget{
    3 ... 
    4 }
    5 //at this case the root element will be found by the locator
    6 //which is declared in superclass
    7 public class UsersOverriddenWidget extends UsersWidget {
    8 ... 
    9 }

    and

    1 @FindBy(relevant locator2) //this locator overrides 
    2 //all locators declared in superclasses
    3 public class UsersOverriddenWidget2 extends UsersWidget {
    4 ... 
    5 }

    Is it possible to reuse "widgets" in crossplatform testing?

    If there is no special details of interaction with an application browser version and/or versions for different mobile OS's then

     1 @FindBy(relevant locator for browser/webview html or by default) 
     2 @AndroidFindBy(relevant locator for Android UI automator)
     3 @iOSFindBy(relevant locator for iOS UI automation)
     4 public class UsersWidget extends Widget {
     5 
     6   @FindBy(relevant locator for browser/webview html or by default) 
     7   @AndroidFindBy(relevant locator for Android UI automator)
     8   @iOSFindBy(relevant locator for iOS UI automation)
     9   RemoteWebElement subElement1;
    10 
    11   @FindBy(relevant locator for browser/webview html or by default) 
    12   @AndroidFindBy(relevant locator for Android UI automator)
    13   @iOSFindBy(relevant locator for iOS UI automation)
    14   RemoteWebElement subElement2;
    15 
    16   //overrides a html/default
    17   //locator declared in the used class
    18   @FindBy(relevant locator for browser/webview html or by default) 
    19   //overrides an Android UI automator
    20   //locator declared in the used class
    21   @AndroidFindBy(relevant locator for Android UI automator) 
    22   //overrides an iOS UI automation
    23   //locator declared in the using class 
    24   @iOSFindBy(relevant locator for iOS UI automation)   
    25   UsersWidget subWidget;
    26 
    27   //and so on..   
    28 }

    What if interaction with a "widget" has special details for each used platform, but the same at high-level

    Then it is possible

    1 public /*abstract*/ class DefaultAbstractUsersWidget extends Widget{
    2 
    3 }

    and

    1 @FindBy(locator)
    2 public class UsersWidgetForHtml extends DefaultAbstractUsersWidget {
    3 
    4 }

    and

    1 @AndroidFindBy(locator)
    2 public class UsersWidgetForAndroid extends DefaultAbstractUsersWidget {
    3 
    4 }

    and even

    1 @iOSFindBy(locator)
    2 public class UsersWidgetForIOS extends DefaultAbstractUsersWidget {
    3 
    4 }

    and then

     1   import io.appium.java_client.pagefactory.OverrideWidget;
     2   ...
     3 
     4   //above is the other field declaration
     5   @OverrideWidget(html = UsersWidgetForHtml.class, 
     6   androidUIAutomator = UsersWidgetForAndroid.class, 
     7   iOSUIAutomation = UsersWidgetForIOS .class)
     8   DefaultAbstractUsersWidget widget;
     9 
    10   //below is the other field/method declaration

    This use case has some restrictions;

    • All classes which are declared by the OverrideWidget annotation should be subclasses of the class declared by field

    • All classes which are declared by the OverrideWidget should not be abstract. If a declared class is overriden partially like

    1   //above is the other field declaration
    2 
    3   @OverrideWidget(iOSUIAutomation = UsersWidgetForIOS .class)
    4   DefaultUsersWidget widget; //lets assume that there are differences of 
    5   //interaction with iOS and by default we use DefaultUsersWidget.
    6   //Then DefaultUsersWidget should not be abstract too.
    7   //
    8 
    9   //below is the other field/method declaration
    • for now it is not possible to
     1   import io.appium.java_client.pagefactory.OverrideWidget;
     2   ...
     3 
     4   //above is the other field declaration
     5   @OverrideWidget(html = UsersWidgetForHtml.class, 
     6   androidUIAutomator = UsersWidgetForAndroid.class, 
     7   iOSUIAutomation = UsersWidgetForIOS .class)
     8   DefaultAbstractUsersWidget widget;
     9 
    10   //below is the other field/method declaration
    11 
    12   //user's code
    13   ((UsersWidgetForAndroid) widget).doSpecialWorkForAndroing()

    The workaround:

     1   import io.appium.java_client.pagefactory.OverrideWidget;
     2   ...
     3 
     4   //above is the other field declaration
     5   @OverrideWidget(html = UsersWidgetForHtml.class, 
     6   androidUIAutomator = UsersWidgetForAndroid.class, 
     7   iOSUIAutomation = UsersWidgetForIOS .class)
     8   DefaultAbstractUsersWidget widget;
     9 
    10   //below is the other field/method declaration
    11 
    12   //user's code
    13   ((UsersWidgetForAndroid) widget.getSelfReference()).doSpecialWorkForAndroing()

    Good! What about widget lists?

    All that has been mentioned above is true for "widget" lists.

    One more restriction

    It is strongly recommended to implement each subclass of io.appium.java_client.pagefactory.Widget with this constructor

    1    public /*or any other available modifier*/ WidgetSubclass(WebElement element) {
    2        super(element);
    3    }
  • 相关阅读:
    统计某个状态最新出现的连续次数
    debian 10 xface 安装输入法
    Temporary failure in name resolution
    Leetcode199二叉树的右视图(宽搜)
    Leetcode200岛屿数量(深搜)
    Leetcode130. 被围绕的区域(深搜)
    Leetcode116. 填充每个节点的下一个右侧节点指针(宽搜或深搜)
    Leetcode之二叉树展开为链表(深搜)
    Leetcode之路径总和II
    vue学习02-v-text
  • 原文地址:https://www.cnblogs.com/superbaby11/p/6098265.html
Copyright © 2011-2022 走看看