Search code examples
appiumwaitimplicitwebdriver-io

How to add something like isClickable() in my appium native app tests


How to add something like isClickable() in my appium native app tests. I have written my tests, however they are very flaky and fail sometimes because it cannot find the element. I am thinking about making custom click and set value functions with the implicit wait times.

I thought about using isClickable() but the appium documentation says - Please note that isClickable works only in web and webviews, it doesn't work in mobile app native context.

Is there any other alternative i can use? can i use smartwait? if yes how can i implement that

Here is how i am defining home.screen.js

import AppScreen from './app.screen';

const SELECTORS = {
    HOME_SCREEN: '~homeBarButton',
    PRODUCTSEARCH_SCREEN: '~productSearchBarButton',
    CUSTOMERSEARCH_SCREEN: '~customersBarButton',
    STOREHUB_SCREEN: '~storeHubBarButton',
    SETTING_ICON: '~SettingsIcon',
    LOGOUT_BUTTON: '~settingsMainLogoutButton'
};

class HomeScreen extends AppScreen {
    constructor () {
        super(SELECTORS.HOME_SCREEN);
    }

    get homescreenButton () {
        return $(SELECTORS.HOME_SCREEN);
    }

    get productsearchField () {
        return $(SELECTORS.PRODUCTSEARCH_SCREEN);
    }

    get customersearchButon () {
        return $(SELECTORS.CUSTOMERSEARCH_SCREEN);
    }

    get storehubButon () {
        return $(SELECTORS.STOREHUB_SCREEN);
    }

    get settingIcon () {
        return $(SELECTORS.SETTING_ICON);
    }

    get logoutButton () {
        return $(SELECTORS.LOGOUT_BUTTON);
    }
}

export default new HomeScreen();

And i am writing my test like this test.js:

import HomeScreen from '../screenobjects/home.screen';
import FormScreen from '../screenobjects/forms.screen';
import CommonPage from '../pageobjects/common.page';

describe('Sending item successfullt,', () => {

    beforeEach(() => {
        CommonPage.login()
    });

    afterEach(() => {
        CommonPage.logout()
    });

    it('should be able to send the item to the mirror', () => {
        driver.pause(3000)
        HomeScreen.productsearchField.click();
        driver.pause(3000)
        HomeScreen.customersearchButon.click();

    });


});

As you can see above, I have to add driver.pause otherwise my tests would fail because of button not clickable or typeable.


Solution

  • Best approach is to stop using implicit waits and do an explicit wait before each driver UI interaction.

    You should do some reading on waitUntil / WebDriverWait (not sure if you have that in node.js implementation).

    Then create functions for interacting with all types of elements in your app that perform an explicit wait before execution.

    Pseudo code:

    get clickButton (Selector element) {
            waitUntil(clickable(element),...);
            return $(driver.click(element));
        }
    

    Write generic methods for all type of elements in your app (button, textfield, dropdown...) and remove implicit waits from driver. You will see a big difference in your test stability.