Search code examples
javascriptioswebdriverappiumwebdriver-io

appium with JS testing, tap by coordinates doesn't work


Basically I'm testing an iOS app on the simulator, wrote in react-native, using appium with XCUITest and webriver.

I noticed I couldn't reach through locators "next" and "previous" button, located on a calendar (used to choose the month), that is placed on a modal.

So I decided to try to tap it through the tap by coordinates strategy: I retrieved the coords with appium inspector, and I've tried the followings:

settings in the config file (notice, if can make any difference, I've set 'appium:nativeWebTap': true:

capabilities = [
    {
        // the path for appium server
        path: '/wd/hub',
        // The defaults you need to have in your config
        platformName: 'iOS',
        maxInstances: 1,
        // For W3C the appium capabilities need to have an extension prefix
        // This is `appium:` for all Appium Capabilities which can be found here
        // http://appium.io/docs/en/writing-running-appium/caps/
        'appium:deviceName': 'iPhone 8',
        'appium:platformVersion': '15.5',
        'appium:orientation': 'PORTRAIT',
        // `automationName` will be mandatory, see
        // https://github.com/appium/appium/releases/tag/v1.13.0
        'appium:automationName': 'XCUITest',
        // The path to the app
        'appium:app': join(process.cwd(), './app_test/myApp.app'),
        
        // Read the reset strategies very well, they differ per platform, see
        // http://appium.io/docs/en/writing-running-appium/other/reset-strategies/
        'appium:noReset': false,
        // How long (in seconds) Appium will wait for a new command from the client before assuming the client quit and ending the session
        // default: 240
        'appium:newCommandTimeout': 500,
        'appium:autoGrantPermissions': true,
        'appium:autoAcceptAlerts': true,
        'appium:nativeWebTap': true,
        // make process headless
        'appium:isHeadless': false,
        'appium:settings[snapshotMaxDepth]': 60
    }

my test file:

describe('Testing', () => {
    it('Test tap', async () => {

        //TEST:
        await driver.setTimeouts(30000)

        // first try
        await driver.touchAction({ action: 'tap', x: 323, y: 225 })
        
        // second try
        await driver.execute('mobile: tap', { x: 323, y: 225 })

        // just to avoid instant disappearing
        await browser.pause(10000)
    })
})

None of the two worked: I mean that no tap happens. I also noticed that while an iphone8 (and so the simulator, I think) has a 750x1334 resolution, the maximum x and y coordinates in the appium inspector are 375x666.

So I just did a proportion

323:375=x:750    //x=646
225:666=x:1334.  //y=451

and i used 646, 451 as cooords, but didn't work.

So, my idea is that the code I wrote simply does not tap at all.

What I'm doing wrong? what's the trick to do a simple TAP with coordinates in appium?


Solution

  • Solved.

    TL:DR; => go to the last block of code, at the bottom of the answer.

    I tried uncountable times, uncountable options, due to the lack of documentation in webdriverIO documentation and appium documentation.

    So, after trying:

        // not working with iphone simulator and XCUITest
        await browser.touchAction({
            action: 'tap',
            x: 295,
            y: 200
        })
    
        // not working with iphone simulator and XCUITest
        await driver.execute('mobile: tap', { x: 600, y: 400 })
    
        // not working with iphone simulator and XCUITest
        await elem.touchAction({ action: 'click', x: 320, y: 290 })
        
        // not working with iphone simulator and XCUITest
        await driver.touchAction({ action: 'tap', x: 295, y: 200 })
    
        // not working with iphone simulator and XCUITest
        await driver.touchAction({ actions: [{ action: 'tap', options: { x: 295, y: 200 } }] })
    

    and at least another dozens of commands, I went to the webdriverio github.

    I found some interesting things, for example here I found the actions list for touchAction command:

    export type ActionTypes = 'press' | 'longPress' | 'tap' | 'moveTo' | 'wait' | 'release';
    

    'release' is a bit different from the others, and must be used like the last example of this page.

    I've also found the only current working way (october, 2022) to tap with JS:

    await driver.touchAction([{ action: 'tap', x: 0, y: 0, element: elementName }])
    

    This function takes in input:

    • an action (one of the ones listed above in ActionTypes)
    • x and y coordinates, in pixel (a number), from the center of an element
    • an element elementName

    all the other examples listed here did not work for me.

    I solved my issue retrieving an element under the < and > calendar buttons and adding or subtracting a bunch of pixel just looking at the screen.

    REMEMBER: x and y values used in appium inspector DO NOT correspond to pixels.

    So, for example, to tap on the < calendar button shown here: calendar

    i had to

    // retrieve sunday block
    // there's no Id on this calendar element
    const sunday = await $(
        '-ios class chain:**/XCUIElementTypeOther[`name == "native.calendar.DAY_NAMES"`]/XCUIElementTypeStaticText[1]'
    )
    
    // just looked at the above screen I thought the left arrow is more or less 20px above, 
    //so from the center of the sunday element:
    await driver.touchAction([{ action: 'tap', x: 20, y: -20, element: sunday }])