Getting StaleObjectException after on test method is over


#1

So , I am getting strange issue in my Framework.
After successfully completion of one test method , it does not shut down the app and start next .
If I run the methods individually it runs successfully .
**Exception which i am getting **

org.openqa.selenium.StaleElementReferenceException: android.support.test.uiautomator.StaleObjectException
at android.support.test.uiautomator.UiObject2.getAccessibilityNodeInfo(UiObject2.java:629)
at android.support.test.uiautomator.UiObject2.getVisibleBounds(UiObject2.java:210)
at android.support.test.uiautomator.UiObject2.getVisibleCenter(UiObject2.java:251)
at android.support.test.uiautomator.UiObject2.click(UiObject2.java:343)
at io.appium.uiautomator2.model.UiObject2Element.click(UiObject2Element.java:44)
at io.appium.uiautomator2.handler.Click.safeHandle(Click.java:40)
at io.appium.uiautomator2.handler.request.SafeRequestHandler.handle(SafeRequestHandler.java:56)
at io.appium.uiautomator2.server.AppiumServlet.handleRequest(AppiumServlet.java:202)
at io.appium.uiautomator2.server.AppiumServlet.handleHttpRequest(AppiumServlet.java:193)
at io.appium.uiautomator2.http.ServerHandler.channelRead(ServerHandler.java:44)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:345)
at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:345)
at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:435)
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:293)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:267)
at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:250)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:345)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1294)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:911)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:131)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:611)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysPlain(NioEventLoop.java:514)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:468)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:438)
at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:140)
at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:144)
at java.lang.Thread.run(Thread.java:818)

My test methods goes like

@Test(priority = 1)

public void validLogin() throws InterruptedException {


    if(loginPage == null)
        loginPage=new LoginPage(driver);

        loginPage.ValidLogin();
}



@Test(priority = 2)
public void InvalidUserId() throws InterruptedException {

    if(loginPage == null)
        loginPage = new LoginPage(driver);

    loginPage.Invaliduser_id();
}

#2

@Piyush_Kumar1 you need CLOSE driver after each test and OPEN it before each test.


#3

That I am already doing in BasePage

@AfterTest
public void tearDown () throws Exception {
driver.quit();
appiumService.stop();
}
Isn’t it enough ?


#4

@Piyush_Kumar1 driver.quit is correct but appiumService.stop move to “afterSuite”. start appiumService in “beforeSuite”.


#5

Okay . So my @Before suit is -
@BeforeTest

    public void setup() throws Exception {


        Properties prop = new Properties();
        InputStream input;
        appiumService = AppiumDriverLocalService.buildDefaultService();
        appiumService.start();
        appiumServiceUrl=appiumService.getUrl().toString();
        System.out.println("Appium server started at " +appiumServiceUrl);

So after every test it should start the server again ?


#6

@Piyush_Kumar1 you need start appium server only one time and stop it afte all tests completed. Not each test.


#7

Yes , I sensed that , now i have changed the annotations to BeforSuite & AfterSuite.
@BeforeSuite
This is my complete BaseClass
public void setup() throws Exception {

        Properties prop = new Properties();
        InputStream input;
        appiumService = AppiumDriverLocalService.buildDefaultService();
        appiumService.start();
        appiumServiceUrl=appiumService.getUrl().toString();
        System.out.println("Appium server started at " +appiumServiceUrl);
        //platform=prop.getProperty("platform");

        try {

            input = new FileInputStream("src/test/java/Utils/appiumSession.properties");
            prop.load(input);

            DesiredCapabilities capabilities = new DesiredCapabilities();
            capabilities.setCapability("automationName", prop.getProperty("automationName"));
            capabilities.setCapability("platformName", prop.getProperty("platformName"));
            capabilities.setCapability("platformVersion", prop.getProperty("platformVersion"));
            capabilities.setCapability("deviceName", prop.getProperty("deviceName"));
            capabilities.setCapability("app", prop.getProperty("app"));
            capabilities.setCapability("newCommandTimeout", "10");


        /* Checking the platform */

       platform = prop.getProperty("platform");
        if (platform.equals("ANDROID")) {

       driver = new AndroidDriver<>(new URL(appiumServiceUrl), capabilities);
        } else if (platform.equals("IOS")) {
            driver = new IOSDriver<>(new URL(appiumServiceUrl), capabilities);
            driver.manage().timeouts().implicitlyWait(15,TimeUnit.SECONDS);


        } else {
            throw new Exception("Unable to read platform");
        }

        PageFactory.initElements(new AppiumFieldDecorator(driver, 5, TimeUnit.SECONDS), this);


    } catch (IOException io) {
        io.printStackTrace();


    }
        System.out.println("platform selected is " + driver);




}


    @AfterSuite
    public void tearDown () throws Exception {


        driver.quit();
        appiumService.stop();
    }

}


#8

@Piyush_Kumar1 is it still any issue?


#9

Yes, the same . Only The test with Priority 1 is running


#10

Okay , I guess i was making mistake by not running the complete suite . Now I have added testng.xml.
But now I am getting

java.lang.IllegalArgumentException: Can not set io.appium.java_client.MobileElement field PageObjects.LoginObjRep.user_id to org.openqa.selenium.remote.RemoteWebElement$$EnhancerByCGLIB$$d27c0df4

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 Pages.LoginPage.<init>(LoginPage.java:26)

Line 26 is where I am instantiating pagefactory objects
PageFactory.initElements(new AppiumFieldDecorator(driver),loginObjRep);

@Aleksei ?


#11

@Piyush_Kumar1 you page object should contain something like:

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

#12

Doing This worked . Thanks


#13

Have this initialisation for the very beginning , but once we moved to UIAutomator2 the StaleElementReferenceException is very annoying.


#14

@igal_epshtein you testing web. Is it? Create your out clicker which repeat request after let say 100ms and up to 5 tries. I make such when had same problem while tests are executed too fast and element appeared but not in dom yet.


#15

Nope, it’s a netive app


#16

@igal_epshtein then pls provide more details :slight_smile: do you see it on clicks or other? steps done before? you need investigate more your client…


#17

Hi @Aleksei,

I’m using io.appium 6.1.0 with selenium-java 3.11.0 and guava 24.0-jre.
I’ve kept capabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, “UiAutomator2”);
I’m using test class and calling individual page classes through the test class in the business functionality order - for loop ( lp.Login() -> functionality() [with different data]-> lop.logout() ) .
‘lp’ is the object of a page class.
The login, the functionality and then logout - each of them are methods of different page classes.
After a flow in a for loop, when the control comes to the login method again, I got: I got **android.support.test.uiautomator.StaleObjectException **
at android.support.test.uiautomator.UiObject2.getAccessibilityNodeInfo(UiObject2.java:629).
I am declaring all mobileelements in the page class and initializing them in the page class specific constructor using PageFactory.initElements(new AppiumFieldDecorator(driver), this);

Now, because the control is again trying to access the elements of the login() method page class, do I have to initialize the elements again ?


#18

I also came across an article here:
https://developer.android.com/reference/android/support/test/uiautomator/StaleObjectException

Here they say that :
A StaleObjectException exception is thrown when a UiObject2 is used after the underlying View has been destroyed. In this case, it is necessary to call findObject(BySelector) to obtain a new UiObject2 instance.

So I think we need to re-initialize the elements.