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    }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM