Getting Appium Driver as Null in PageFactory method

Hi All,

hope you all are well,
I need your help, I am try to run the IOS Automation with Appium in the MacBook using a simulator and every time I execute the test case getting this error
Complete Error
Step failed
io.cucumber.core.exception.CucumberException: Failed to instantiate class stepdefinations.InStoreLoginStepdef
at io.cucumber.core.backend.DefaultObjectFactory.cacheNewInstance(DefaultObjectFactory.java:67)
at io.cucumber.core.backend.DefaultObjectFactory.getInstance(DefaultObjectFactory.java:45)
at io.cucumber.java.AbstractGlueDefinition.invokeMethod(AbstractGlueDefinition.java:47)
at io.cucumber.java.JavaStepDefinition.execute(JavaStepDefinition.java:29)
at io.cucumber.core.runner.CoreStepDefinition.execute(CoreStepDefinition.java:66)
at io.cucumber.core.runner.PickleStepDefinitionMatch.runStep(PickleStepDefinitionMatch.java:63)
at io.cucumber.core.runner.ExecutionMode$1.execute(ExecutionMode.java:10)
at io.cucumber.core.runner.TestStep.executeStep(TestStep.java:85)
at io.cucumber.core.runner.TestStep.run(TestStep.java:57)
at io.cucumber.core.runner.PickleStepTestStep.run(PickleStepTestStep.java:51)
at io.cucumber.core.runner.TestCase.run(TestCase.java:84)
at io.cucumber.core.runner.Runner.runPickle(Runner.java:75)
at io.cucumber.core.runtime.Runtime.lambda$executePickle$6(Runtime.java:128)
at io.cucumber.core.runtime.CucumberExecutionContext.lambda$runTestCase$5(CucumberExecutionContext.java:129)
at io.cucumber.core.runtime.RethrowingThrowableCollector.executeAndThrow(RethrowingThrowableCollector.java:23)
at io.cucumber.core.runtime.CucumberExecutionContext.runTestCase(CucumberExecutionContext.java:129)
at io.cucumber.core.runtime.Runtime.lambda$executePickle$7(Runtime.java:128)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at io.cucumber.core.runtime.Runtime$SameThreadExecutorService.execute(Runtime.java:249)
at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:112)
at io.cucumber.core.runtime.Runtime.lambda$runFeatures$3(Runtime.java:110)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
at java.util.stream.SliceOps$1$1.accept(SliceOps.java:204)
at java.util.ArrayList$ArrayListSpliterator.tryAdvance(ArrayList.java:1361)
at java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:126)
at java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:499)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:486)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
at io.cucumber.core.runtime.Runtime.runFeatures(Runtime.java:111)
at io.cucumber.core.runtime.Runtime.lambda$run$0(Runtime.java:82)
at io.cucumber.core.runtime.Runtime.execute(Runtime.java:94)
at io.cucumber.core.runtime.Runtime.run(Runtime.java:80)
at io.cucumber.core.cli.Main.run(Main.java:87)
at io.cucumber.core.cli.Main.main(Main.java:30)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at io.cucumber.core.backend.DefaultObjectFactory.cacheNewInstance(DefaultObjectFactory.java:53)
… 37 more
Caused by: java.lang.IllegalArgumentException: Can not set io.appium.java_client.MobileElement field pageobjects.InstoreLogin.homepage_heading to null value
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:81)
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 pageobjects.InstoreLogin.(InstoreLogin.java:24)
at stepdefinations.InStoreLoginStepdef.(InStoreLoginStepdef.java:19)
… 42 more

These are my code files to look at

PageFactory- InstoreLogin
package pageobjects;

import base.TestDriverSession;
import io.appium.java_client.AppiumDriver;
import io.appium.java_client.FindsByIosNSPredicate;
import io.appium.java_client.MobileElement;
import io.appium.java_client.pagefactory.AppiumFieldDecorator;
import io.appium.java_client.pagefactory.iOSXCUITFindBy;

import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;

import java.time.Duration;
import java.util.Set;

public class InstoreLogin extends TestDriverSession{

public InstoreLogin() {
    //driver=initializeDriver("iOS");

    **PageFactory.initElements(new AppiumFieldDecorator(driver,Duration.ofSeconds(10)),this);** //**getting driver null**
    System.out.println(driver);

}
@iOSXCUITFindBy(accessibility = "Dealer Sign-in")
private MobileElement homepage_heading;





@iOSXCUITFindBy(xpath = "//XCUIElementTypeApplication[@name=\"Instore Sales\"]/XCUIElementTypeWindow/XCUIElementTypeOther/XCUIElementTypeOther/XCUIElementTypeOther/XCUIElementTypeOther/XCUIElementTypeOther/XCUIElementTypeOther/XCUIElementTypeOther/XCUIElementTypeTextField")
private MobileElement dealer_mob;

@iOSXCUITFindBy(xpath = "//XCUIElementTypeApplication[@name=\"Instore Sales\"]/XCUIElementTypeWindow/XCUIElementTypeOther/XCUIElementTypeOther/XCUIElementTypeOther/XCUIElementTypeOther/XCUIElementTypeOther/XCUIElementTypeOther/XCUIElementTypeOther/XCUIElementTypeSecureTextField")
private MobileElement dealer_password;

@iOSXCUITFindBy(xpath = "//XCUIElementTypeApplication[@name=\"Instore Sales\"]/XCUIElementTypeWindow[1]/XCUIElementTypeOther/XCUIElementTypeOther/XCUIElementTypeOther/XCUIElementTypeOther/XCUIElementTypeOther/XCUIElementTypeOther/XCUIElementTypeOther/XCUIElementTypeOther/XCUIElementTypeOther[1]/XCUIElementTypeButton[1]")
private MobileElement MakeItYours;

@FindBy(name="New Configuration")
private MobileElement newconfiguration;

GenericUtility utility=new GenericUtility();

public void InstoreHeading()
{
System.out.println(“page object started”);

    String heading=homepage_heading.getText();
    System.out.println("get the heading of dealer homepage :"+heading);
}


public void dealerLogin()
{

    utility.waitForVisibility(dealer_mob);
    dealer_mob.clear();
    dealer_mob.setValue("9110049730");

   utility.waitForVisibility(dealer_password);
    dealer_password.clear();
    dealer_password.setValue("9110049730");

    homepage_heading.click();

    MobileElement dealer_login= (MobileElement) ((FindsByIosNSPredicate)driver).findElementByIosNsPredicate("label == \"Login\"");

    dealer_login.click();
}

public void clickMakeItYours()
{
    utility.waitForVisibility(MakeItYours);
    if(MakeItYours.isDisplayed())
    {
        MakeItYours.click();
    }
}

public void clickNewConfiguration() throws InterruptedException {
utility.waitForVisibility(newconfiguration);
newconfiguration.click();
Thread.sleep(2000);
Set contHandle=driver.getContextHandles();

for(String contextHandles:contHandle)
{
    System.out.println(contextHandles);
}
driver.context(contHandle.toArray()[1].toString());

System.out.println("context switching from native to web :"+driver.getContext());
Thread.sleep(4000);

}

}

DriverSessionFile
package base;
import io.appium.java_client.AppiumDriver;
import io.appium.java_client.MobileElement;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.ios.IOSDriver;
import io.appium.java_client.remote.MobileCapabilityType;
import org.openqa.selenium.remote.DesiredCapabilities;

import java.io.File;
import java.net.URL;

public class TestDriverSession {

public static AppiumDriver driver;
public static AppiumDriver initializeDriver(String platformName) throws Exception {
    DesiredCapabilities caps = new DesiredCapabilities();
    caps.setCapability(MobileCapabilityType.PLATFORM_NAME, platformName);
    //     caps.setCapability("newCommandTimeout", 300);

    URL url = new URL("http://0.0.0.0:4723/wd/hub");

    switch(platformName){
        case "Android":
            caps.setCapability(MobileCapabilityType.DEVICE_NAME, "Pixel 3");
            caps.setCapability(MobileCapabilityType.AUTOMATION_NAME, "UiAutomator2");
            caps.setCapability(MobileCapabilityType.UDID, "emulator-5554");
            String andAppUrl = System.getProperty("user.dir") + File.separator + "src" + File.separator + "main"
                    + File.separator + "resources" + File.separator + "ApiDemos-debug.apk";
            caps.setCapability("appPackage", "io.appium.android.apis");
            caps.setCapability("appActivity", "io.appium.android.apis.ApiDemos");
            caps.setCapability(MobileCapabilityType.APP, andAppUrl);
           return new AndroidDriver(url, caps);
        case "iOS":
            // caps.setCapability(MobileCapabilityType.PLATFORM_NAME,"iOS");
            caps.setCapability(MobileCapabilityType.DEVICE_NAME,"iPad");
            caps.setCapability(MobileCapabilityType.AUTOMATION_NAME,"XCUITest");
            caps.setCapability(MobileCapabilityType.UDID,"912F76BD-52A8-4D10-B179-3FCF36BD9FB6");
            String appURL="/Users/avishsharma/Desktop/latest/Instore_Sales.app";
caps.setCapability("simulatorStartupTimeout", 180000);
            caps.setCapability("bundleId","com.royalenfield.instoresales");
            caps.setCapability("includeSafariInWebviews",true);
            //caps.setCapability("fullReset", "true");
            //caps.setCapability("webviewConnectTimeout", "90000");

            return new IOSDriver(url, caps);
        default:
            throw new Exception("invalid platform");
    }
}

}

Application Hooks file
package hooks;

import base.TestDriverSession;
import io.appium.java_client.AppiumDriver;
import io.appium.java_client.ios.IOSDriver;
import io.cucumber.java.After;
import io.cucumber.java.Before;
import io.cucumber.java.Scenario;

import java.util.Properties;

public class ApplicationHooks {

public static AppiumDriver driver;

Properties properties;

public TestDriverSession dsession;

@Before
public void initialize(Scenario scenario) throws Exception {
    dsession=new TestDriverSession();
    driver=dsession.initializeDriver("iOS");
    System.out.println("print driver from hooks file :"+driver);
    System.out.println("hooks started");
    System.out.println("scenario started is :"+scenario.getName());

}

@After
public void quit() {
    System.out.println("stopping driver");
}

}

This is my stepdefination file
package stepdefinations;

import base.TestDriverSession;
import io.appium.java_client.AppiumDriver;
import io.cucumber.java.en.And;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import pageobjects.InstoreLogin;

public class InStoreLoginStepdef extends TestDriverSession {

InstoreLogin ilogin=new InstoreLogin();
@Given("User goes to the in-store login page")
public void user_goes_to_the_in_store_login_page() {
    System.out.println("given step defination started");
    ilogin.InstoreHeading();
}

Can you guys please suggest why pageobject init method giving this error every time and why it refers to null?? NOTE: Only hook initialisation method is working, once code moves to step definition then getting the above error

it looks like an issue with your execution order, you know the code best, try to track it. make sure you initialize the driver before calling new InstoreLogin()

additionally, you can add to initializeDriver method a validation to check if the driver is already initialized.
something like: if (driver != null) return driver; then, if it is null the method will get executed.
then, you can call this method as much as you want and it will be safe and will make sure the driver is initialized once!
after that, you’ll be able to call this method in initializeDriver’s constructor without any hesitations.
here: (just uncomment your comment.)

@ido_oserovitz Thanks for your suggestion, I get your point, but the problem I am facing if I uncommented the driver=initializeDriver(“iOS”); in the page factory initialisation constructor then it works fine only in 1 condition that I have to uncomment the same line in the Application Hooks file. Then it works fine but will be the good approach to pass the driver like this in the PageFactory Constructor?

you don’t have to pass the driver in the constructor, you can initialize it once and make it global for all your test packages.
if you’ll do as I suggested, you should be able to uncomment driver=initializeDriver(“iOS”); in both the hook and the constructor.

otherwise, I cannot help much, I do not know your order of execution and what each utility/class should do…