This is the third in a series of posts that discuss using Appium with Sauce Labs. Chapter 1 covered Language Bindings; Chapter 2 discusses Touch Actions; this chapter covers Testing Hybrid Apps & Mobile Web; and Chapter 4 is about Advanced Desired Capabilities. Mobile applications can be purely native, or web applications running in mobile browsers, or a hybrid of the two, with a web application running in a particular view or set of views within a native application. Appium is capable of automating all three types of applications, by providing different "contexts" in which commands will be interpreted.
context specifies how the server interprets commands, and which commands are available to the user. Appium currently supports two contexts: native and webview. Both of these are handled by different parts of the system, and may even proxy commands to another framework (such as webviews on Android, which are actually served by a managed ChromeDriver instance). It is important to know what context you are in, in order to know how you can automate an application.
Native contexts refer to native applications, and to those parts of hybrid apps that are running native views. Commands sent to Appium in the native context execute against the device vendor’s automation API, giving access to views and elements through name, accessibility id, etc. As well, in this context commands to interact directly with the device, to do operations such as changing the wifi connect or setting the location, can be used. These very powerful operations are not available within the context of a webview.
In addition to native and hybrid applications, the native context can be accessed in a mobile web app, in order to have some of the methods only available there. In this case it is important to understand that the commands are not running against the web application running in the browser, but rather are interacting with the device and the browser itself.
There are two types of webviews. The first is the bulk of a mobile web application. Indeed, all automation of a mobile web application is done within a webview context, though one can switch into the native context in order to take advantage of some of Appium’s features for automating the device and handling the application life cycle. The second type of webview is that part of a hybrid application that is inside a UIAWebView (for iOS) or android.webkit.WebView (for Android). In the webview context the commands that can be used are the standard WebDriver commands, giving access to elements through css selectors and other web-specific locators such as link text.
Mobile web is essentially a specialized version of a hybrid application. What would be the native portion of a hybrid application is the browser itself! As you automate your application you can step out into the native context in order to interact with the browser or with the device itself. But when you begin automating a mobile web application Appium automatically takes you into the webview context. If you have a hybrid application that begins in a webview, you can have the same functionality by automatically entering into the initial webview by using the
autoWebview desired capability set to
true. Otherwise the automation script will need to first enter into webview before interacting with any elements.
To move between contexts there is a method that takes the string name of the context to which you want to switch. The native context will have the name “NATIVE_APP” while the available webview contexts will have a name like
WEBVIEW_1 (for iOS) or
WEBVIEW_io.appium.android.apis (for Android, where
io.appium.android.apis is the running activity). The generic
WEBVIEW will choose the first available webview. This is not necessary when automating a mobile web browser
[code language=”python”] # switch to first available webview driver.switch_to.context(“WEBVIEW_1″) [/code]
Once in the webview context Selenium commands to interact with a web application can be used.
[code language=”python”] driver.find_element_by_css_selector(‘.some_class’) driver.find_element_by_partial_link_text(‘Home Page’) [/code]
The source at this point will be the html of the page loaded into the webview view, or the mobile web browser.
To return to the native context (which is not necessary for automating mobile web applications), you use the same command as used to get into the webview, but asking to switch to the native context.
[code language=”python”] # switch back to native context driver.switch_to.context(“NATIVE_APP”) [/code]
Now, in the native context, if you get the source you will get an xml document describing all the elements in the view itself, not the html even if there is html being rendered in that view!
It is possible to get a list of the available contexts, and choose the one to which to switch from those. This has the added bonus of making your tests capable of handling changes in context naming, and being the same across platforms. There will always be one (and only one) native context, named
NATIVE_CONTEXT, and zero or more webview contexts, all of which will start with
[code language=”python”] webview = driver.contexts.last driver.switch_to.context(webview) [/code]
Finally, you can retrieve the current context in order to make sure you are in the correct place, and to programmatically switch contexts at the correct time.
[code language=”python”] current_context = driver.context
# or current_context = driver.current_context [/code]
If your mobile environment supports tabbed browsing, as mobile Chrome does on Android, the tabs are accessible through the
window commands in a webview context, just as in desktop browser automation!
[code language=”python”] # enter into the webview webview = driver.contexts.last driver.switch_to.context(webview)
# cycle through the tabs for tab in driver.window_handles: driver.switch_to.window(tab)
# return to native context driver.switch_to.context(“NATIVE_APP”) [/code]
The main thing about switching from a native context into a webview is that subsequent commands get proxied to a Selenium WebDriver session automating the browser which backs the webview. This makes it possible to run any webdriver commands that you would like! For instance, in a native context you cannot find an element using a css selector, but in a webview context that is perfectly reasonable. The underlying source for the app at that point is the html of the web page being displayed!
But Appium has a number of methods that are not available to normal webdriver. In order to take advantage of these methods one must be in a native context so that Appium itself handles the request, rather than a proxy.