Skip to content
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

Closed
ashishkumar1000 opened this issue Jul 31, 2014 · 40 comments
Closed

Unable to initialise PageFactory for PageObject #73

ashishkumar1000 opened this issue Jul 31, 2014 · 40 comments

Comments

@ashishkumar1000
Copy link

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 ???

@amedvedjev
Copy link

same problem

@TikhomirovSergey
Copy link
Contributor

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
PageFactory.initElements

PageObject po = new PageObject();
PageFactory.initElements(new AppiumFieldDecorator(driver),po)

Please pay attention: PageFactory.initElements is "void".

@amedvedjev
Copy link

"You should istantiate your "page object" before " - before what?

let say in test class we have following

Abstract Page:

public abstract class Page {
protected AppiumDriver driver;
public Page(AppiumDriver driver) {
this.driver = driver;
}
}

Test Page:

public class FirstPage extends Page {
@findby(id = "something")
private List elemList;
public FirstPage(AppiumDriver driver) {
super(driver);
}
//some staff
}

Test class:

private FirstPage firstPage;
@test
public void doTest() {
// was before: firstPage = PageFactory.initElements(driver, FirstPage.class);
PageFactory.initElements(new AppiumFieldDecorator(driver), FirstPage.class);
}

@TikhomirovSergey
Copy link
Contributor

Ok.
Let see two different examples below:

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.

@amedvedjev
Copy link

thanks!

@amedvedjev
Copy link

Sergey,

still not clear how to initiate pages one by one inside test class?

I can't start this with every page change.
/**
* Attention please
*/
po = PageFactory.initElements(new AppiumDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities), PageObject.class);

mine example:

Abstract Page:

public abstract class Page {
protected AppiumDriver driver;
public Page(AppiumDriver driver) {
this.driver = driver;
PageFactory.initElements(new AppiumFieldDecorator(driver), this);
}
}

Test Page:

public class FirstPage extends Page {
@findby(id = "something")
private List elemList;
public FirstPage(AppiumDriver driver) {
super(driver);
}
//some staff
}

Test class:

public class testDoTests extends AppiumSetup {
private FirstPage firstPage;
private SecondPage secondPage;
@test
public void doTest1() {
firstPage = PageFactory.initElements(driver, FirstPage.class); // CRASH HERE!
//do some tests on first page
secondPage = PageFactory.initElements(driver, SecondPage.class);
//do some tests on second page
}
}

Appium Setup class:

public class AppiumSetup {
protected static AppiumDriver driver = null;
driver = new AppiumDriver(new URL("http://0.0.0.0:4723/wd/hub"), capabilities);
}

@TikhomirovSergey
Copy link
Contributor

Please, let me see stacktrace.

@amedvedjev
Copy link

java.lang.RuntimeException: java.lang.InstantiationException: com.cardola.tests.page.android.KeywordPage
at org.openqa.selenium.support.PageFactory.instantiatePage(PageFactory.java:136)
at org.openqa.selenium.support.PageFactory.initElements(PageFactory.java:66)
at com.cardola.tests.test.android.testKeywordPage.testKeywordPage(testKeywordPage.java:22)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:84)
at org.testng.internal.Invoker.invokeMethod(Invoker.java:714)
at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:901)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1231)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:127)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:111)
at org.testng.TestRunner.privateRun(TestRunner.java:767)
at org.testng.TestRunner.run(TestRunner.java:617)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:348)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:343)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:305)
at org.testng.SuiteRunner.run(SuiteRunner.java:254)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1224)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1149)
at org.testng.TestNG.run(TestNG.java:1057)
at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:111)
at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:204)
at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:175)
at org.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:125)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
Caused by: java.lang.InstantiationException: com.cardola.tests.page.android.KeywordPage
at java.lang.Class.newInstance0(Class.java:342)
at java.lang.Class.newInstance(Class.java:310)
at org.openqa.selenium.support.PageFactory.instantiatePage(PageFactory.java:133)
... 32 more

@TikhomirovSergey
Copy link
Contributor

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!

@TikhomirovSergey
Copy link
Contributor

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
at org.openqa.selenium.support.PageFactory.instantiatePage(PageFactory.java:136)
at org.openqa.selenium.support.PageFactory.initElements(PageFactory.java:66)
at io.appium.java_client.Test2.test(Test2.java:68)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: java.lang.InstantiationException
at sun.reflect.InstantiationExceptionConstructorAccessorImpl.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Unknown Source)
at org.openqa.selenium.support.PageFactory.instantiatePage(PageFactory.java:131)
... 26 more

@TikhomirovSergey
Copy link
Contributor

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

@amedvedjev
Copy link

so you reproduced same problem with:

at org.openqa.selenium.support.PageFactory.instantiatePage(PageFactory.java:136)
at org.openqa.selenium.support.PageFactory.initElements(PageFactory.java:66)

Questions:

  • Do you want me to try make code changes as with your succeeded example?
  • or do i need wait for a fix?

@TikhomirovSergey
Copy link
Contributor

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);
PageFactory.PageFactory.initElements(new AppiumFieldDecorator(driver), po);

The reason I will describe over five minutes.

@TikhomirovSergey
Copy link
Contributor

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
@AndroidFindBy(someLocator)
//iOSFildBy(someLocator)
WebElement semeElement

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. 
  }

@lolemouine
Copy link

Still not understanding how I could use PageFactory with other classes...

@TikhomirovSergey
Copy link
Contributor

Hi @lolemouine !

I am trying to understand your situation too...

It is impossible to use PageFactory with parameters:

  • FieldDecorator;
  • Class

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)

?
It is possible. Do you want to use new FindBy annotations (see this: #68) and it will solve your problems? If yes, you have to make some improvement of your code anyway.

For now the legal way is (with org.openqa.selenium.support.PageFactory):
(1)

Pageobject po = new PageObject(webdriver and some parameters);
PageFactory.initElements(new AppiumFieldDecorator(webdriver), po);

or
(2)

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 

https://github.com/SeleniumHQ/selenium/blob/master/java/client/src/org/openqa/selenium/support/pagefactory/DefaultFieldDecorator.java

@lolemouine
Copy link

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 !

@lolemouine
Copy link

I have java-client 1.6.0. But it seams that eclipse doesn't recognize AppiumPageFactory neither

@TikhomirovSergey
Copy link
Contributor

Because AppiumPageFactory doesn't exist. But it could be created.

PageFactory doesn't work with class or PageFactory doesn't work with Class on Appium ? This is different issues.

Ok! Page factory works with class and Webdriver instance like

PageFactory.initElements(Singleton.getInstance().getDriver(), LoginPage.class);

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.
Please read about Selenium PageFactory class. At least I gave links to Selenium github.

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.

@lolemouine
Copy link

OK, and it's really impossible to add AppiumPageFactory to java-client ? Or to add it to Appium?

@lolemouine
Copy link

All right, I tried with the instance, and it works for me, but we still have more coding to do that way...

@lolemouine
Copy link

I will create my AppiumPageFactory ! I understand wath you mean now !

@TikhomirovSergey
Copy link
Contributor

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.

@ashishkumar1000
Copy link
Author

Any work arounds with iOS ?
I am still facing issues in implementing Page Factory for iOS.

@TikhomirovSergey
Copy link
Contributor

@ashishkumar1000
What issues are you facing?

@Jonahss Jonahss closed this as completed Sep 29, 2014
@mbelyaeva91
Copy link

Did someone manage to implement Page Factory for iOS so far?

@amedvedjev
Copy link

we do not have any problem with iOS and Android.

@mbelyaeva91
Copy link

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

@amedvedjev
Copy link

"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.
sample you follow is not perfect for creating multiple pages.

@JasonSmiley208
Copy link

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).

public class AgentLoginPage extends BasePageClass {

    @iOSFindBy(xpath = "//UITextFieldLabel[@label = 'Email']")
    public static MobileElement emailInput;

    @iOSFindBy(xpath = "//UITextFieldLabel[@label = 'Password']")
    public static MobileElement passwordInput;

    public static void initialize(){
        // driver is pulled in from BasePageClass.
        PageFactory.initElements(new AppiumFieldDecorator(driver), AgentLoginPage.class);
    }

    @When("^I submit a \"(.*)\" agent login form$")  //Code for Cucumber.
    public static void I_submit_a_X_agent_login_form(String loginType){
        String email = "", password = "";

        switch (loginType.toLowerCase()){
            case "valid":
                email = "[email protected]";
                password = "Password";
                break;
            default:
                throw new PendingException("Unknown Login Type: " + loginType);
        }

        emailInput.sendKeys(email);   //NullPointerException here
        passwordInput.sendKeys(password);

        passwordInput.sendKeys(Keys.ENTER); //Submits form

    }
}

In my before Hooks:

        AppiumDriverLocalService service = AppiumDriverLocalService.buildDefaultService();
        service.start();

        DesiredCapabilities capabilities = new DesiredCapabilities();
        capabilities.setCapability(MobileCapabilityType.BROWSER_NAME, "");
        capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "9.2");
        capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "iPhone 6 Plus");
        capabilities.setCapability(MobileCapabilityType.APP, appPath);
        capabilities.setCapability("name", "Java iOS tutorial " + date);

        driver = new IOSDriver(service.getUrl(), capabilities);

        driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
        AgentLoginPage.initialize();

Can I not do this via a static variable? I would think it would be a non issue.

@amedvedjev
Copy link

@JasonSmiley208 you do init in wrong place.

simplest example:

public abstract class Page {

    protected WebDriver driver;

    public Page(WebDriver driver) {
        this.driver = driver;
        PageFactory.initElements(new AppiumFieldDecorator(driver, 20, TimeUnit.SECONDS), this);
    }
}

public class MainPage extends Page {

    //Action bar
    @AndroidFindBy(id = "action_bar_title")
    private List<AndroidElement> actionBarTitle;

    //List Elements
    @AndroidFindBy(id = "list")
    private List<AndroidElement> listView;
    @AndroidFindBy(id = "text1")
    private List<AndroidElement> cellText;

    public MainPage(WebDriver driver) {
        super(driver);
    }

    public boolean isMainPageLoaded() {
        return !actionBarTitle.isEmpty() && !listView.isEmpty();
    }
}

public class BaseTest {
    protected static AppiumDriver driver = null;
    private static DesiredCapabilities capabilities = null;
    ....

    @BeforeMethod(alwaysRun=true)
    public void beforeMethod(ITestContext iTestContext) {
        capabilities = DesiredCapabilities.android();
        capabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, "Appium");
        capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android");
        capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, MobilePlatform.ANDROID);
        File appDir = new File(userDir, fileName);
        capabilities.setCapability(MobileCapabilityType.APP, appDir.getAbsolutePath());
        capabilities.setCapability(MobileCapabilityType.APP_WAIT_ACTIVITY, ".ApiDemos");
        capabilities.setCapability("fullReset", true);
        capabilities.setCapability("noReset", true);

        driver = new AndroidDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);
    }

    @AfterMethod(alwaysRun=true)
    public void afterMethod(ITestResult iTestResult, ITestContext iTestContext) throws Exception {
        try {
            driver.quit();
        } catch (Exception e) {}
    }

    //... so on continue with @BeforeSuite, @AfterSuite, ..... whatever needed
}

public class test_1 extends BaseTest {
    private MainPage mainPage;

    @Test
    public void testMainPage() {
        mainPage = PageFactory.initElements(driver, MainPage.class);
        assertTrue("Main screen NOT loaded", mainPage.isMainPageLoaded());
   }
}

@JasonSmiley208
Copy link

Quick question - I see you are using

mainPage = PageFactory.initElements(driver, MainPage.class);

instead of

new AppiumFieldDecorator(driver)

Is that intended or a typo?

Or is this because you are using the Page(Webdriver) constructor?

@amedvedjev
Copy link

are you sure - ?
see:

public Page(WebDriver driver) {
        this.driver = driver;
        PageFactory.initElements(new AppiumFieldDecorator(driver, 20, TimeUnit.SECONDS), this);
    }

@idcmurali
Copy link

I am trying to setup POM with Appium and running into issue .
I used the same code provided by TikhomirovSergey commented on Jul 31, 2014 ( Says : This code works) But I still get the Pagefactory error message . It is also looking and saying source jar not found looking in my selenium-server-standalone jar3.0.1

java.lang.IllegalArgumentException: Can not set static io.appium.java_client.MobileElement field wfm.appium.testcases.FinalApp$LandPageObject.CreateAccountnew to com.sun.proxy.$Proxy6
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
at sun.reflect.UnsafeStaticObjectFieldAccessorImpl.set(UnsafeStaticObjectFieldAccessorImpl.java:79)
at java.lang.reflect.Field.set(Field.java:764)
at org.openqa.selenium.support.PageFactory.proxyFields(PageFactory.java:117)
at org.openqa.selenium.support.PageFactory.initElements(PageFactory.java:105)
at org.openqa.selenium.support.PageFactory.initElements(PageFactory.java:92)
at org.openqa.selenium.support.PageFactory.initElements(PageFactory.java:79)
at org.openqa.selenium.support.PageFactory.initElements(PageFactory.java:65)
at wfm.appium.testcases.FinalApp.test(FinalApp.java:73)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

@klzeng
Copy link

klzeng commented Jul 7, 2017

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:
protected BasePage(AndroidDriver<AndroidElement> driver){ this.driver = driver; PageFactory.initElements(new AppiumFieldDecorator(driver, 5, TimeUnit.SECONDS), this); }

LoginPage extends BasePage:
`
@AndroidFindBy(id = "et_login_username")
private AndroidElement usernameField;

public LoginPage(AndroidDriver driver){
super(driver);
}`

In LoginTest:
`@Override
@BeforeClass
public void setUpPage() {

objLogin = new LoginPage(driver);

}
And I got NoSuchMethodError on usernameField.sendKeys(strUsername);`

Appreciate it if you could help out!

@rmeenasuresh
Copy link

rmeenasuresh commented Jul 10, 2017

Hi i got the same error NoSuchMethodError. please anyone help me. i upgrade dependencies to latest versions .

Pageobjectpage,
Note: static import the iosDriver
Class LoginPage(){
public LoginPage() {
PageFactory.initElements(new AppiumFieldDecorator(iosDriver,15, TimeUnit.SECONDS), this);}

@iOSFindBy(xpath="//XCUIElementTypeButton[7]")
private MobileElement Number1Btn;

public void login(){
Number1Btn.click();
}
}

LoginTest

public class LoginTest extends BaseTest{
private LoginPage loginPage;
@BeforeClass
public void setup()
{
loginpage = new LoginPage();
}

@test
public void loginTest()
{
loginPage.login();-----------------this line shows Nosuch method error
}

my reports,

java.lang.NoSuchMethodError: org.openqa.selenium.support.ui.FluentWait.until(Lcom/google/common/base/Function;)Ljava/lang/Object;
at io.appium.java_client.pagefactory.AppiumElementLocator.waitFor(AppiumElementLocator.java:88)
at io.appium.java_client.pagefactory.AppiumElementLocator.findElement(AppiumElementLocator.java:103)
at io.appium.java_client.pagefactory.interceptors.InterceptorOfASingleElement.intercept(InterceptorOfASingleElement.java:57)
at io.appium.java_client.ios.IOSElement$$EnhancerByCGLIB$$184e91dc.click()

@narendra-chandratre
Copy link

Its still reproducible on Appium 1.8.1 :(
Anyone resolve this?

@dikako
Copy link

dikako commented Jul 6, 2020

This Working with Me, My Project Selenium, TestNG and Appium use PageFactory.initElements

public class Login extends Setup {

    @Test
    public void loginAlert() throws InterruptedException {
        

    Button button = new Button(driver);
            PageFactory.initElements(driver, button);
            Input input = new Input(driver);
            PageFactory.initElements(driver, input);
        
        
        Input input1 = new Input(driver);
        System.out.println("Test Alert Login");
        button.ById("navigation_more");
        button.ById("btnLogin");
        input.ById("et_email_or_phone_number", "dikakoko.com");
        input1.ById("tet_password", "dikakoko");
        
    }
}

Below this is the function I called above.

public class Input {
    AppiumDriver<MobileElement> driver;
    Root root = new Root();

    public Input(AppiumDriver<MobileElement> driver) {
        this.driver = driver;
    }

    public void ById(String selector, String textValue) {
        MobileElement element = driver.findElement(By.id(root.element() + ":id/" + selector));
        waitForVisible(driver, element);
        Actions actions = new Actions(driver);
        actions.moveToElement(element);
        actions.click();
        actions.sendKeys(textValue);
        actions.build().perform();
        System.out.println("Input: " + textValue);
    }
    
    private void waitForVisible(AppiumDriver<MobileElement> driver, MobileElement element) {
        try {
            Thread.sleep(5000);
            System.out.println("Waiting for element visibility");
            WebDriverWait wait = new WebDriverWait(driver, 20);
            wait.until(ExpectedConditions.visibilityOf(element));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

and This


public class Button {

    AppiumDriver<MobileElement> driver;
    Root root = new Root();

    public Button(AppiumDriver<MobileElement> driver) {
        this.driver = driver;
    }

    public void ById(String selector) {
        MobileElement element = driver.findElement(By.id(root.element() + ":id/" + selector));
        Actions actions = new Actions(driver);
        actions.moveToElement(element);
        actions.click();
        actions.build().perform();
        System.out.println("Button is Clicked!");
    }
}

I Use This

             Button button = new Button(driver);
            PageFactory.initElements(driver, button);
            Input input = new Input(driver);
            PageFactory.initElements(driver, input);

References : www.seleniumeasy.com

@MukeshHalaPlay
Copy link

MukeshHalaPlay commented Feb 17, 2022

Try these steps: This might help (Works in my case with same initElement NoSuchMethod Exception)

Open Eclipse>
Windows>
Preferences>
Java>
Installed JREs>
Change the selected JRE to the JDK: (Follow the steps:)
Add the Java folder(C:\Program Files\Java\jdk-11.0.14) as JDK (Installed)
Select that added JDK, then Apply and close.

image

Try retest your scripts after this change.

@Demudu1995
Copy link

Demudu1995 commented Oct 30, 2022

Hai guys any one please help me !
I'm not able to use appiumfielddecorator, if I use appiumfielddecorator, I'm getting this exception:
java.lang.ExceptionInInitializerError at
io.appium.java_client.pagefactory.u tils.ProxyFactory.getEnhanced Prox y(ProxyFactory.java:53)

: I am automating Mobile app (Android ).
So If I use
PageFactory.initElements (driver, this);
and try to find elements by using annotation as @findby MY CODE WORKS.

But if try to use
PageFactory.initElements (new
AppiumFieldDecorator (driver), this);
and try to find elements by using annotation as @AndroidFindBy
My CODE is not working, and
I'm getting the exception java.lang.ExceptionInInitializerError.

I'm using jdk version 17
Java client 8.2.0
Appium also latest 1.2.3
This is my code :
public class Page1 { // page object class

public static AppiumDriver driver;

public Page1(AppiumDriver driver) {
    PageFactory.initElements(new AppiumFieldDecorator(driver), this);
    this.driver = driver;
}


@AndroidFindBy(id = "com.tva.z5:id/homeIcon")
public WebElement homeIcon;

public void logo() {
    homeIcon.click();

}

}


package appiumtests; // this is my test

public class Test1 {

@Test
public void test() throws InterruptedException {

    Page1 lg = new Page1(driver);

      lg.logo();
    Thread.sleep(5000);

}

}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests