Search code examples
javaseleniumappiumpageobjects

Illegal Argument Exception in Appium framework


After (foolishly) upgrading Appium Server along with various project libraries, such that I cannot tell which, if any, caused the problem, my previously running Appium framework suddenly started failing upon attempting to locate any elements.

The server starts (either manually via desktop or through the java code) and it launches my emulator (if not already loaded), makes the connection, opens the app (in the case show, simply settings) and fails as soon as it tries to validate that the settings main page is displayed by checking the existence of the "Settings" text:

Given the settings app is displayed (FAILED) (java.lang.IllegalArgumentException: Can not set io.appium.java_client.android.AndroidElement field com.mindtree.pageobjects.SettingsMainPage.header to org.openqa.selenium.remote.RemoteWebElement$$EnhancerByCGLIB$$d27c0df4)

The Appium server versions for both desktop and nodeJS is currently 1.7.2 I believe the problem started when I was originally at 1.7.1 or 1.7.2 and it succeeded in doing an auto-update on the desktop version to 1.8.1.

Selenium version is 3.11.0 (tried various flavors from 3.9.0 through 3.13.0)

Appium Java client is 6.0.0-BETA5 (tried 6.0.0-BETA4, 6.0.0, 6.1.0)

Java is 1.8

The JBehave test step that reports the error:

@Given("the settings app is displayed")
public void givenTheSettingsAppIsDisplayed() {
    main = new SettingsMainPage(driver);
    if (main.pageLoaded())
        test.logGivenPass("the settings app is displayed");
    else {
        test.logGivenFail("the settings app is displayed");
        fail();
    }
}

The corresponding page object snippet:

public class SettingsMainPage extends MobilePageObject {

    public SettingsMainPage(AndroidDriver<AndroidElement> driver) {
        super(driver);
        System.out.println("Settings Main page class has been initialized");
    }

    @AndroidFindBy(xpath = "//android.widget.TextView[@text='Settings']")
    AndroidElement header;
    @AndroidFindBy(id= "android:id/title")
    List<AndroidElement> titles;
    @AndroidFindBy(id= "android:id/summary")
    List<AndroidElement> summaries;

    public Boolean pageLoaded() {
        return helper.isDisplayed(header);
    }

}

Googling this particular error returns a few hits, but no offered solutions.

Any guidance appreciated.

edit: I should add that the failure seems to happen upon initialization of the page object via the page factory, since the text "initialized" is never shown, it fails while trying to initialize all the page elements, specifically the first one, at least according to the error message.

My base page object is below:

import java.time.Duration;

import org.openqa.selenium.support.PageFactory;

import com.mindtree.helpers.AppiumUtils;

import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.android.AndroidElement;
import io.appium.java_client.pagefactory.AppiumFieldDecorator;

public class MobilePageObject {

    AndroidDriver<AndroidElement> driver;
    AppiumUtils helper;

    public MobilePageObject(AndroidDriver<AndroidElement> driver) {

        this.driver = driver;
        PageFactory.initElements(new AppiumFieldDecorator(driver, Duration.ofSeconds(15)), this);
        helper = new AppiumUtils();

    }

}

Edit Update: Downgraded the Appium Server through NodeJS from 1.7.2 to 1.7.1. Result: no change, same error reported.


Solution

  • I am using Appium server 1.8.1, selenium 3.13.0 and java client 6.1.0. I use the page object model like following and it works fine.

    public class SettingsMainPage{
    
        public SettingsMainPage(AndroidDriver<AndroidElement> driver) {
            PageFactory.initElements(new AppiumFieldDecorator(driver), this);
            System.out.println("Settings Main page class has been initialized");
        }
    
        @AndroidFindBy(xpath = "//android.widget.TextView[@text='Settings']")
        AndroidElement header;
        @AndroidFindBy(id= "android:id/title")
        List<AndroidElement> titles;
        @AndroidFindBy(id= "android:id/summary")
        List<AndroidElement> summaries;
    
        public boolean pageLoaded() {
           try{
    
               (new WebDriverWait(driver, 20)).until(ExpectedConditions.visibilityOfElementLocated(header));
               return header.isDisplayed();
           }
           catch(Exception e){
               return false;
           }
        }
    
    }
    

    And you must define your desiredCapabilities like following:

    public static AppiumDriver<MobileElement> driver;
    public static AppiumDriver<MobileElement> setupDesiredCapabilities(String appPackage, String appActivity,
                                                                           String udid, String platformVersion, boolean noReset) {
    
            DesiredCapabilities caps = new DesiredCapabilities();
    
            caps.setCapability("deviceName", "Android phone");  //any name
            caps.setCapability("udid", udid);   
            caps.setCapability("platformName", "Android");
            caps.setCapability("platformVersion", platformVersion);
            caps.setCapability("appPackage", appPackage);
            caps.setCapability("appActivity", appActivity);
            caps.setCapability("noReset", noReset);    //optional
    
    
            try {
                driver = new AndroidDriver<MobileElement>(new URL(
                        "http://127.0.0.1:4723/wd/hub"), caps);
    
            } catch (MalformedURLException e) {
                //
            } catch (Exception ex) {
                //
            }
    
            return driver;
        }
    

    Make sure you have define static AppiumDriver and use the same driver object to call constructor of each page.