It's easy to forget that Appium is used not only for native apps but also for testing websites by automating mobile browsers like iOS's Mobile Safari. And Appium's support of the WebDriver API for Safari is so extensive that it's easy to forget it's not the exact same thing as Selenium!
One clue that this is happening to you is when you encounter the following scenario:
- You find an element (no element not found error)
- You click the element (no error thrown on click)
- Nothing happens in your app
To work around this and other related issues, Appium has a special capability: nativeWebTap. When it is set to true, Appium will perform some magic behind the scenes any time you call click() on an element found in the browser. It will essentially try to determine the location of that element on the webpage, translate that location to native screen coordinates, account for any system bars and the like, and then generate a native (XCUITest-driven) tap on that location. If all goes well, the result is that the iOS subsystems detect a touch at a certain place, pass that info on to Safari, which then determines that an element has been tapped.
The net result is that you should be back in business: you'll be able to trigger your app's action and continue testing the user flow. You might also feel a little sense of satisfaction that you generated a more "real" tap! (Or not--what's really real when it comes to testing?)
Because Appium has to do some mathematicky stuff to make nativeWebTap work, it's best not to use the capability unless you have some reason to. And an alternative approach might be to simply bug your app developer and ask them if they used some non-standard touch handler, and whether they could just stop and do things the normal way instead. Another option would be to simply fight fire with fire (pun very much intended): figure out what event the developer decided the element is listening for, and fire that event on the element yourself using executeScript! It's up to you--either way, Appium's got you covered.
If you're interested in seeing this discrepancy yourself (with and without nativeWebTap), have a look at the full code example for this edition. (I don't reproduce it here since the only item of interest is the use of the capability itself).