-
-
Notifications
You must be signed in to change notification settings - Fork 764
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Unable to initialise PageFactory for PageObject #73
Comments
same problem |
Hi! Let see this (is taken from here https://github.com/SeleniumHQ/selenium/blob/master/java/client/src/org/openqa/selenium/support/PageFactory.java): * @param pageClassToProxy A class which will be initialised.
* @return An instantiated instance of the class with WebElement and List<WebElement> fields proxied
*/
public static <T> T initElements(WebDriver driver, Class<T> pageClassToProxy)
/**
* As
* {@link org.openqa.selenium.support.PageFactory#initElements(org.openqa.selenium.WebDriver, Class)}
* but will only replace the fields of an already instantiated Page Object.
*
* @param driver The driver that will be used to look up the elements
* @param page The object with WebElement and List<WebElement> fields that should be proxied.
*/
public static void initElements(WebDriver driver, Object page)
/**
* Similar to the other "initElements" methods, but takes an {@link ElementLocatorFactory} which
* is used for providing the mechanism for fniding elements. If the ElementLocatorFactory returns
* null then the field won't be decorated.
*
* @param factory The factory to use
* @param page The object to decorate the fields of
*/
public static void initElements(ElementLocatorFactory factory, Object page)
/**
* Similar to the other "initElements" methods, but takes an {@link FieldDecorator} which is used
* for decorating each of the fields.
*
* @param decorator the decorator to use
* @param page The object to decorate the fields of
*/
public static void initElements(FieldDecorator decorator, Object page) You should istantiate your "page object" before PageObject po = new PageObject();
PageFactory.initElements(new AppiumFieldDecorator(driver),po) Please pay attention: PageFactory.initElements is "void". |
"You should istantiate your "page object" before " - before what? let say in test class we have following Abstract Page: public abstract class Page { Test Page: public class FirstPage extends Page { Test class: private FirstPage firstPage; |
Ok. public class Test {
public static class PageObject {
private final WebDriver driver;
@FindBy(className = "android.widget.TextView")
private WebElement element;
public PageObject(WebDriver driver){
this.driver = driver;
}
public void click(){
element.click();
}
}
private PageObject po;
@Before
public void setup() throws Exception {
File appDir = new File("src/test/java/io/appium/java_client");
File app = new File(appDir, "ApiDemos-debug.apk");
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(MobileCapabilityType.BROWSER_NAME, "");
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");
capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, "Android");
capabilities.setCapability(MobileCapabilityType.APP, app.getAbsolutePath());
/**
* Attention please
*/
po = PageFactory.initElements(new AppiumDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities), PageObject.class);
}
@org.junit.Test
public void test() {
po.click();
}
@After
public void tearDown() throws Exception {
po.driver.quit();
}
} If you use PageFactory only with @findby, there is nothing to change. Your example will work well without AppiumFieldDecorator. But... Are you sure that all your browser locators are suitable for Android\iOS native\hybrid app? /**
*
* Imagine, that we have application API Demos with the same UI
* But different locators (browser/Android)
*
*/
public class Test2 {
public static class PageObject {
private final WebDriver driver;
@FindBy(className = "someDOMClass")
@AndroidFindBy(className = "android.widget.TextView")
private WebElement element;
public PageObject(WebDriver driver){
this.driver = driver;
/**
* Attention please
*/
PageFactory.initElements(new AppiumFieldDecorator(driver), this);
}
public void click(){
element.click();
}
}
private PageObject po;
@Before
public void setup() throws Exception {
File appDir = new File("src/test/java/io/appium/java_client");
File app = new File(appDir, "ApiDemos-debug.apk");
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(MobileCapabilityType.BROWSER_NAME, "");
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");
capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, "Android");
capabilities.setCapability(MobileCapabilityType.APP, app.getAbsolutePath());
/**
* Attention please
*/
po = new PageObject(new AppiumDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities));
}
@org.junit.Test
public void test() {
po.click();
}
@After
public void tearDown() throws Exception {
po.driver.quit();
} AppiumFieldDecorator decorates Webelement-fields which marked by @AndroidFindBy/@iOSFindBy. This decorator supports @findby too. |
thanks! |
Sergey, still not clear how to initiate pages one by one inside test class? I can't start this with every page change. mine example: Abstract Page: public abstract class Page { Test Page: public class FirstPage extends Page { Test class: public class testDoTests extends AppiumSetup { Appium Setup class: public class AppiumSetup { |
Please, let me see stacktrace. |
java.lang.RuntimeException: java.lang.InstantiationException: com.cardola.tests.page.android.KeywordPage |
It looks strange.... public static abstract class AbstractPageObject {
protected final WebDriver driver;
public AbstractPageObject(WebDriver driver){
this.driver = driver;
/**
* Attention please
*/
PageFactory.initElements(new AppiumFieldDecorator(driver), this);
}
}
public static class PageObject extends AbstractPageObject {
public PageObject(WebDriver driver) {
super(driver);
}
@FindBy(className = "android.widget.TextView")
private WebElement element;
public void click(){
element.click();
}
}
protected static AppiumDriver driver;
@Before
public void setup() throws Exception {
File appDir = new File("src/test/java/io/appium/java_client");
File app = new File(appDir, "ApiDemos-debug.apk");
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(MobileCapabilityType.BROWSER_NAME, "");
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");
capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, "Android");
capabilities.setCapability(MobileCapabilityType.APP, app.getAbsolutePath());
driver = new AppiumDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);
}
@org.junit.Test
public void test() {
PageObject po = PageFactory.initElements(driver, PageObject.class);
po.click();
}
} This code works! |
I could reproduce the similar exception on this code: public static abstract class AbstractPageObject {
protected final WebDriver driver;
public AbstractPageObject(WebDriver driver){
this.driver = driver;
/**
* Attention please
*/
PageFactory.initElements(new AppiumFieldDecorator(driver), this);
}
}
//!!!
public static abstract class PageObject extends AbstractPageObject {
public PageObject(WebDriver driver) {
super(driver);
}
@FindBy(className = "android.widget.TextView")
private WebElement element;
public void click(){
element.click();
}
}
protected static AppiumDriver driver;
@Before
public void setup() throws Exception {
File appDir = new File("src/test/java/io/appium/java_client");
File app = new File(appDir, "ApiDemos-debug.apk");
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(MobileCapabilityType.BROWSER_NAME, "");
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");
capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, "Android");
capabilities.setCapability(MobileCapabilityType.APP, app.getAbsolutePath());
driver = new AppiumDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);
}
@org.junit.Test
public void test() {
PageObject po = PageFactory.initElements(driver, PageObject.class);
po.click();
} java.lang.RuntimeException: java.lang.InstantiationException |
How does your code fall? See listing from Selenium: private static <T> T instantiatePage(WebDriver driver, Class<T> pageClassToProxy) {
try {
try {
Constructor<T> constructor = pageClassToProxy.getConstructor(WebDriver.class);
return constructor.newInstance(driver);
} catch (NoSuchMethodException e) {
return pageClassToProxy.newInstance(); //cause
}
} catch (InstantiationException e) {
throw new RuntimeException(e); //thrown
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
} |
so you reproduced same problem with: at org.openqa.selenium.support.PageFactory.instantiatePage(PageFactory.java:136) Questions:
|
Please, make sure that your target class is not abstract and has constructor like this: new PageObject(driver) Anyway, the best way to use AppiumDecorator is (if it really need to be used, I wrote above): po = new PageObject(some params); The reason I will describe over five minutes. |
So, let see this code: * @see FindBy
* @see CacheLookup
* @param driver The driver that will be used to look up the elements
* @param pageClassToProxy A class which will be initialised.
* @return An instantiated instance of the class with WebElement and List<WebElement> fields proxied
*/
public static <T> T initElements(WebDriver driver, Class<T> pageClassToProxy) {
T page = instantiatePage(driver, pageClassToProxy); (1)
initElements(driver, page); (2)
return page;
} At (1) constructor of page object will populate fields. You attempted to use this public Page(AppiumDriver driver) {
this.driver = driver;
PageFactory.initElements(new AppiumFieldDecorator(driver), this);
}
} If there is a field at (2) it turns into null because of *
* @param driver The driver that will be used to look up the elements
* @param page The object with WebElement and List<WebElement> fields that should be proxied.
*/
public static void initElements(WebDriver driver, Object page) {
final WebDriver driverRef = driver;
initElements(new DefaultElementLocatorFactory(driverRef), page); //(!!!)
//All webelement fields which
//are not annotated by @FindBy turn into null here
//This is made by Selenium developers. It is so frustrating.
} |
Still not understanding how I could use PageFactory with other classes... |
Hi @lolemouine ! I am trying to understand your situation too... It is impossible to use PageFactory with parameters:
The only way (using class, not instance) is: PageFactory.initElements(driver, pageClassToProxy) Details are described above. Is it possible that you are using not default PageFactory (from org.openqa.selenium.support)? Your code is compiled but throws some exception. So let me see stack trace. It would be nice if I could see sources of your custom PageFactory class. Maybe... Do you want to use AppiumPageFactory that has method like this: AppiumPageFactory.initElements(new AppiumFieldDecorator(driver), ClassToProxy.class) ? For now the legal way is (with org.openqa.selenium.support.PageFactory): Pageobject po = new PageObject(webdriver and some parameters);
PageFactory.initElements(new AppiumFieldDecorator(webdriver), po); or public PageObject(someParams){
//staff
PageFactory.initElements(new AppiumFieldDecorator(driver), this);
}
//at automated test
PageObject pageObject = new PageObject(someParams); instead of PageFactory.initElements(webdriver, Pageobject.class); //it is the same as (1)
//or (2) but with Selenium DefaultFieldDecorator inside |
PageFactory doesn't work with class or PageFactory doesn't work with Class on Appium ? This is two different issues. This would work on google chrome from a computer and selenium : PageFactory.initElements(Singleton.getInstance().getDriver(), LoginPage.class Singleton.getInstance().getDriver() would be my driver... TKs ! |
I have java-client 1.6.0. But it seams that eclipse doesn't recognize AppiumPageFactory neither |
Because AppiumPageFactory doesn't exist. But it could be created.
Ok! Page factory works with class and Webdriver instance like
But it doesn't work with Class and FieldDecorator implementation (AppiumFieldDecorator) because there is no suitable method (only with an instance of the class). This method is not implemented by Selenium developers. It is sad. But I am agree that it would be useful method. So if there is an issue it should be fixed on Selenium side. It is my opinion. |
OK, and it's really impossible to add AppiumPageFactory to java-client ? Or to add it to Appium? |
All right, I tried with the instance, and it works for me, but we still have more coding to do that way... |
I will create my AppiumPageFactory ! I understand wath you mean now ! |
Oops! I have just thought about new PageFactory class for Appium! But I'm not sure that there are many projects where usage of page object instance instead of class is difficult. So I will keep track of situation... Maybe it will be implemented. |
Any work arounds with iOS ? |
@ashishkumar1000 |
Did someone manage to implement Page Factory for iOS so far? |
we do not have any problem with iOS and Android. |
I tried to follow the examples above and nothing works for me. What if we have more than one page? Do I initialize them all in @before setUp()? I followed this sample https://github.com/appium/sample-code/blob/master/sample-code/examples/java/junit/src/test/java/com/saucelabs/appium/iOSPageObjectTest.java and it works fine with one page. I still don't get how to deal with multiple pages |
"I tried to follow the examples above and nothing works for me. What if we have more than one page? Do I initialize them all in @before setUp()?" - NOT. you should do this in test code. |
There is so much going on in this thread that its hard to follow what we are saying is broken and what should be working so I am just going to provide my code and can someone explain why I am getting a NullPointerException? (Note, I have a similar setup in a selenium project and no issues).
In my before Hooks:
Can I not do this via a static variable? I would think it would be a non issue. |
@JasonSmiley208 you do init in wrong place. simplest example:
|
Quick question - I see you are using
instead of
Is that intended or a typo? Or is this because you are using the Page(Webdriver) constructor? |
are you sure - ?
|
I am trying to setup POM with Appium and running into issue . java.lang.IllegalArgumentException: Can not set static io.appium.java_client.MobileElement field wfm.appium.testcases.FinalApp$LandPageObject.CreateAccountnew to com.sun.proxy.$Proxy6 |
Hi @TikhomirovSergey , I use the "legal way"(2) you mentioned above, but it doesn't work, I got noSuchMethod error when using sendKeys. In Abstract BasePage: LoginPage extends BasePage: public LoginPage(AndroidDriver driver){ In LoginTest:
} Appreciate it if you could help out! |
Hi i got the same error NoSuchMethodError. please anyone help me. i upgrade dependencies to latest versions . Pageobjectpage, @iOSFindBy(xpath="//XCUIElementTypeButton[7]") public void login(){ LoginTest public class LoginTest extends BaseTest{ @test my reports, java.lang.NoSuchMethodError: org.openqa.selenium.support.ui.FluentWait.until(Lcom/google/common/base/Function;)Ljava/lang/Object; |
Its still reproducible on Appium 1.8.1 :( |
This Working with Me, My Project Selenium, TestNG and Appium use PageFactory.initElements
Below this is the function I called above.
and This
I Use This
References : www.seleniumeasy.com |
Try these steps: This might help (Works in my case with same initElement NoSuchMethod Exception) Open Eclipse> Try retest your scripts after this change. |
Hai guys any one please help me ! : I am automating Mobile app (Android ). But if try to use I'm using jdk version 17
} package appiumtests; // this is my test public class Test1 {
|
I have updated the java-client jar and tried to initialise PageFactory as mention below.
PageObject PageObject1 = PageFactory.initElements(new AppiumFieldDecorator(driver),PageObject.class);
But I am getting type mismatch error.
Is there something I am missing ???
The text was updated successfully, but these errors were encountered: