How to Automate a Real E2E User Flow with Appium for iOS Devices

Sauce AI for Test Authoring: Move from intent to execution in minutes.|xBack to ResourcesBlogPosted

February 17, 2026 · 10 min read · Mobile Testing

Sauce AI for Test Authoring: Move from intent to execution in minutes.

|

x

Back to Resources

Blog

Posted November 21, 2019

How to Automate a Real E2E User Flow with Appium for iOS Devices

quote

This berth is specific to iOS apps. For Android apps, see my other place onhow to automatize a existent E2E user flow on Android

A question I get a lot present is“ Why should I use Appium instead of aboriginal frameworks like Espresso and XCUITest? ”

Normally I would give you my opinion right aside, but throughout the years I ’ ve learned that it ’ s better to come with some facts. There are a lot of fact that I can use to explain why you should opt one or the other, but that ’ s a subject for a different blog.

Today I need to concenter on one specific thing that youcannotdo with native frameworks, and that isautomate a real end-to-end (E2E) user flowing.To preclude this station from becoming a novel, I will merely focus on iOS in my examples. Android will be handled in a freestanding post.

What is a real E2E exploiter flow?

You might be wondering what I intend by areal E2E exploiter flow. Well, the answer is pretty uncomplicated. Let me show you an example. It is based on another question I get a lot from our client aroundautomating the exploiter flow between app and browser, also known as amulti-app-flow

In this example, a user needs to do something in the (native) app which activate opening a browser where the flow proceeds. This can be whatever flow where you exactly require to shift from your app to the browser.

To mimic this flow we impart a link in our that opens a link in the browser. If you install the app and log in you can open the menu and see the following selection.

the menu

Image 1: Menu

When the Aboutitem is exhort, the browser will be opened, which will lead you to our Sauce Labs website. Here you can search our site, click on buttons, get text and so on.

SwagLabs gif

Automating areal E2E user flow

Before we dive into code, I need to mention that Appium can be used with different frameworks and different coding languages. The following coding example will use WebdriverIO as a fabric and JavaScript as a coding language. I tried to keep all steps as generic potential so you might be capable to translate them back to your preferred framework/coding language.

I always start with writing down the functional flowing in comments to get a better understanding, see below.

describe (& # x27; Appium & # x27;, () = & gt; {

it (& # x27; should be able to work with the browser that is open by the app & # x27;, () = & gt; {

// 1. Login to the app

// 2. Verify that you are logged in

// 3. Open the menu and click on the about screen

// 4. Figure out how we can verify that the browser is open

// 5. Verify that the page is laden

   });

});

The first three step can easily be implemented. The difficult part is step 4, where we need toswitch from the app to the browserand determine if this win. If we look at this in a technical way, we could say that we alter from anativecircumstance to awebcontext. When I was refer this out loud I thought that this is almost the same behaviour as you have with Hybrid apps. A Hybrid app besides has anative and a webcontext, the final is called aWebview

So I essay to figure out if switching from anapp to the browserdid the same for the contexts as it would ordinarily do for Hybrid apps by implementing this piece of codification at step 4.

/**

* ` waitUntil ` expects a stipulation and waits until that condition is

* action with a truthy value. So just log the contexts for 15 seconds and see what happens

*/

driver.waitUntil (() = & gt; {

// Get all the contexts, that could seem like this

const contexts = driver.getContexts ();

// Log them to the console

   console.log (& # x27; contexts = & # x27;, context);

// Just return false so this function will ne'er return a truthy value

homecoming false;

}, 15000);


It result in the following log:

contexts = [& # x27; NATIVE_APP & # x27;]

setting = [& # x27; NATIVE_APP & # x27;, & # x27; WEBVIEW_76851.4 & # x27;, & # x27; WEBVIEW_76851.5 & # x27;]

contexts = [& # x27; NATIVE_APP & # x27;, & # x27; WEBVIEW_76851.1 & # x27;, & # x27; WEBVIEW_76851.4 & # x27;, & # x27; WEBVIEW_76851.5 & # x27;]

This was full and bad. The good thing was that I could see that between when the app was closed and when the browser was opened, new contexts were added. But now I had a challenge, the same challenge you might have with Hybrid apps, and that is multiple Webviews. Because how should I ascertain which Webview holds which url?

Two challenges

As said, we have a challenge with the Webviews, but luckily we are apply Appium together with iOS and there is a specific capacity that might help us with this. In March I say an article on Appium Pro about thefullContextList-capability. What it basically execute is that if you provide fullContextList: true, in your capabilities for iOS, and your ask for the current setting, it willnotreturn an array ofcontext-strings, but an array ofWebview-objectscontaining theid, the title and the urlof the Webview that are lade. The advantage of this is that you don ’ t require to recover the title and url with extra Webdriver-calls, but you can retrieve it with one Webdriver call. This makes it much faster and less flakey.

When I started my iOS gimmick with this new capability and checked the contexts again I found this in my logs.

// The first try

setting = [

{id: & # x27; NATIVE_APP & # x27;},

{id: & # x27; WEBVIEW_76851.1 & # x27;, title: & # x27; & # x27;, url: & # x27; about: lacuna & # x27;},

{id: & # x27; WEBVIEW_76851.4 & # x27;, title: & # x27; & # x27;, url: & # x27; about: blank & # x27;},

{id: & # x27; WEBVIEW_76851.5 & # x27;, title: & # x27; & # x27;, url: & # x27; about: lacuna & # x27;}

]

// The second try

contexts = [

{id: & # x27; NATIVE_APP & # x27;},

{id: & # x27; WEBVIEW_76851.1 & # x27;,

rubric: & # x27; Cross Browser Testing, Selenium Testing, Mobile Testing | Sauce Labs & # x27;,

url: & # x27; https: //saucelabs.com/ & # x27;},

{id: & # x27; WEBVIEW_76851.4 & # x27;, title: & # x27; & # x27;, url: & # x27; about: blank & # x27;},

{id: & # x27; WEBVIEW_76851.5 & # x27;, title: & # x27; & # x27;, url: & # x27; about: space & # x27;}

]

The & # x27;about: blank& # x27; s are from multiple empty open tabloid in Safari.

As you can see, this make it lots easier to select the right Webview. You can select the correct Webview with some JavaScript Array legerdemain, like below:

// Store the correct context into this variable

const correctWebview = driver.getContexts ()

// Then filter out the & # x27; NATIVE_APP & # x27;, because it doesn ’ t have a ` url `

.filter (context = & gt; {

return! context.id.includes (& # x27; NATIVE_APP & # x27;)

SUSA automates exploratory testing with persona-driven behavior, catching bugs that scripted automation misses.

               })

// Now notice the webview that contains the correct URL

.find (context = & gt; {

homecoming context.url.includes (& # x27; https: //saucelabs.com/ & # x27;)

               });

The above code will supply the matching Webview selected out of many. We can then use the id to swap to the right Webview setting with the following code in JavaScript:

driver.switchContext (correctWebview.id);

and interact with the browser like we usually do. This mean we can use the like locators and selectors like we would use on a desktop web page, but…… I made a small thinking error which led to my 2d challenge.

A Webview uses Safari, but Safari is not a Webview, meaning my test failed because it could not interact with the webpage in Safari. After some digging I launch out that this was something that was missing in Appium, so I filed bug, seehere. The Appium team added a new capableness in Appium 1.15.0 ringincludeSafariInWebviews. It does what it describes, it will add Safari as a Webview which should fix the issue I was face and eventually it did solve my 2d challenge.

So by adding two extra potentiality and updating my Appium version to the latest 1.15.0 version (which too supports iOS 13) I am now able to automate areal E2E user flowing with Appium

The complete code

In the end I was able to automatise theexistent E2E user flow with Appiumwith the undermentioned code for iOS.

// ============

// Capabilities

// ============

config.capabilities = [

   {

deviceName: & # x27; iPhone X & # x27;,

platformName: & # x27; iOS & # x27;,

platformVersion: & # x27; 12.2 & # x27;,

orientation: & # x27; PORTRAIT & # x27;,

app: join (process.cwd (), & # x27; ./apps/iOS.Simulator.SauceLabs.Mobile.Sample.app.2.1.0.app.zip & # x27;),

maxInstances: 1,

// The 2 duplicate added capabilities

// Return an array of Webview-objects containing the id, the rubric and the url

fullContextList: true,

// Add Safari as a Webview

includeSafariInWebviews: true,

   },

];


import LoginScreen from & # x27; .. /screenObjects/login & # x27;

import InventoryListScreen from & # x27; .. /screenObjects/inventoryList & # x27;

import Menu from & # x27; .. /screenObjects/menu & # x27;;

const DEFAULT_TIMEOUT = 15000;

describe (& # x27; Appium & # x27;, () = & gt; {

it (& # x27; should be able to work with the browser that is open by the app & # x27;, () = & gt; {

// Login to the app and verify that it succeeded

LoginScreen.waitForIsShown ();

LoginScreen.signIn ({username: & # x27; standard_user & # x27;, password: & # x27; secret_sauce & # x27;});

InventoryListScreen.waitForIsShown ();


await (InventoryListScreen.isShown ()) .toEqual (true);

// Open the menu and click on the about screen

Menu.open ();

Menu.openAbout ();

// Now do all the context legerdemain

let correctWebview = nothing;

       /**

* Wait until the correct context with the right url has loaded

* This ` waitUntil ` will wait until the condition of the provided

* function will return true, in our case it will retrovert true if

* the ` correctWebview ` contains a value

        */

       driver.waitUntil (() = & gt; {

// Get all the setting, that could look like this

           // [

           //     {

// id: & # x27; NATIVE_APP & # x27;,

           //     },

           //     {

// id: & # x27; WEBVIEW_74323.1 & # x27;,

// title: & # x27; Smashing Magazine — For Web Designers And Developers — Smashing Magazine & # x27;,

// url: & # x27; https: //www.smashingmagazine.com/ & # x27;,

           //     },

           //     {

// id: & # x27; WEBVIEW_74323.2 & # x27;,

// title: & # x27; Cross Browser Testing, Selenium Testing, Mobile Testing | Sauce Labs & # x27;,

// url: & # x27; https: //saucelabs.com/ & # x27;,

           //     },

           //  ]

const contexts = driver.getContexts ();

// Store the correct context into this varying

// if there is no lucifer don & # x27; t do anything

correctWebview = contexts

// First filter out the & # x27; NATIVE_APP & # x27;

.filter (context = & gt; {

return! context.id.includes (& # x27; NATIVE_APP & # x27;)

               })

// Now filter out the webview that contains the correct URL

.find (context = & gt; {

return context.url.includes (& # x27; https: //saucelabs.com/ & # x27;)

               });

// If the ` correctWebview ` contains a value this function will evaluate to ` true ` meaning

// the ` waitUntil ` can stop

homecoming correctWebview || faithlessly;

}, DEFAULT_TIMEOUT);

// Now switch to the right context

driver.switchContext (correctWebview.id);

ask (driver.getTitle ()) .toEqual (& # x27; Cross Browser Testing, Selenium Testing, Mobile Testing | Sauce Labs & # x27;);

   });

});

Closing remark

With this representative, I shared how to automate an end-to-end user flow employ Appium, which is not something you can do with native model. This isn ’ t to say that you shouldn ’ t use aboriginal frameworks like Espresso and XCUITest, because each creature has its own pros/cons and impart concern value. You could yet use native frameworks and Appium together, each covering a different aim. I just need to show you the powerfulness of use Appium. And the beauty of Appium is that there might be more ways to automateE2E exploiter flows,so if you know a different way, please let us know and share your experiences.

I hope you found this tech tip utilitarian. If you ’ re looking for a flying and easy way to test real E2E user flows with your own app on iOS, you cantry for freewith Sauce Labs. Until future time….happy examination!

Wim Selles help solve mechanisation challenge by day—and practices his passion for front-end test automation at night. Wim enjoys creating his own node.js modules and contributing to open source projects. You can find Wim on LinkedIn and Twittter @ wswebcreation.

Wim Selles

Staff Product Manager at Sauce Labs

Published:
Nov 21, 2019
Share this position
Copy Share Link
LinkedIn
© 2026 Sauce Labs Inc., all rights reserved. SAUCE and SAUCE LABS are registered trademarks owned by Sauce Labs Inc. in the United States, EU, and may be registered in other jurisdictions.
robot
quote

Automate This With SUSA

Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts needed.

Try SUSA Free

Test Your App Autonomously

Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts.

Try SUSA Free