Visual Studio App Center Test is the next generation of Xamarin Test Cloud! Read the blog post.

Calabash Web Views

PDF for offline use
Related APIs:
Related Links:

Let us know how you feel about this

Translation Quality


0/250

Describes how to use the Calabash APIs to interact with web views in a mobile app.

Overview

Calabash provides a powerful query language for locating and interaction with views in native mobile applications. However, some mobile apps are hybrid apps that use web views to display HTML to the user. Android provides the android.webkit.WebView, while iOS applications may use either UIWebView or WKWebView. UIWebKit is older and compatible with all versions of iOS, while WKWebKit is for iOS 8 and higher.

Interacting with web views is a bit more involved as it requires first querying the screen for the native web view widget on the screen, and then locating DOM elements contained in the web view.

Web View APIs in Calabash

Calabash provides three different API's to interact with web views:

  • CSS – This API uses CSS selectors to locate DOM elements displayed by the web view.
  • XPath – Calabash can use XPath expressions to locate DOM elements in the web view.
  • JavaScript – It is possible for a Calabash query to interact with the DOM using JavaScript.

CSS and XPath

The CSS and XPath API both have a similar format:

<CALABASH QUERY> [css|xpath]:'[CSS SELECTOR | XPATH EXPRESSION]'

The <CALABASH QUERY> is a Calabash query that will locate the web view. It is followed by the css or xpath keyword to identify which API Calabash should use to search the DOM, and then the selector or expression that should be used to reference the DOM elements.

If the Calabash query is unable to locate the view, or if the CSS selector is unable to match any of the DOM elements in the view an empty array will be returned.

CSS

The CSS API allows tests to query for a DOM id, class, or tag name. For example, the following Android activity contains an android.webkit.WebView to display some HTML:

This Calabash query will match the H1 DOM element that is displayed:

irb(main):003:0> query "webView css:'H1'"
[
    [0] {
              "class" => "",
           "nodeType" => "ELEMENT_NODE",
                 "id" => "",
        "textContent" => "H1 Header!",
               "html" => "<h1>H1 Header!</h1>",
               "rect" => {
              "bottom" => 82,
                   "y" => 423,
               "right" => 320,
                   "x" => 72,
            "center_x" => 540,
               "width" => 936,
              "height" => 114,
                 "top" => 44,
                "left" => 8,
            "center_y" => 480
        },
           "nodeName" => "H1",
            "webView" => "webView"
    }
]

XPath

XPath is a very powerful API for searching the DOM, but can be a bit more difficult to use compared to the CSS API. An XPath expression is used along with a Calabash query to match elements in the DOM.

The following snippet is an example of how to match the H1 DOM element from the previous section using XPath:

irb(main):003:0> query("webView xpath:'//h1'")
[
    [0] {
              "class" => "",
           "nodeType" => "ELEMENT_NODE",
                 "id" => "",
        "textContent" => "H1 Header!",
               "html" => "<h1>H1 Header!</h1>",
               "rect" => {
              "bottom" => 82,
                   "y" => 423,
               "right" => 320,
                   "x" => 72,
            "center_x" => 540,
               "width" => 936,
              "height" => 114,
                 "top" => 44,
                "left" => 8,
            "center_y" => 480
        },
           "nodeName" => "H1",
            "webView" => "webView"
    }
]

JavaScript

It is possible to locate DOM elements using JavaScript. The JavaScript API is different between iOS and Android and is covered in more detail in the sections below.

JavaScript and iOS

In order to locate DOM elements, the query method is invoked using a Calabash query to reference the web view and a Ruby has that will hold the JavaScript that should be executed. The hash must contain one key, calabashByStringEvalutingJavascript, the value of which is a string containing the JavaScript expression to evaluate:

query "<CALABASH QUERY>", {calabashStringByEvaluatingJavaScript: '<JAVASCRIPT>'}

Calabash will run the JavaScript in the web view and return an array holding the results of the JavaScript call.

As an example, consider the following screenshot which displays some HTML in a UIWebView:

The following snippet shows how to query for the H1 DOM element:

> javascript =  "document.getElementsByTagName('h1').toString()"
> query("UIWebView", {calabashStringByEvaluatingJavaScript: javascript})
[
    [0] "[object NodeList]"
]

JavaScript and Android

Calabash provides the evaluate_javascript method which takes a Calabash query to locate the web view, and a string containing the JavaScript expression to evaluate:

evaluate_javascript("<CALABASH QUERY>", "<JAVASCRIPT>")

As an example, consider the following screenshot which displays some HTML in a WebView widget:

The following snippet will query for the H1 DOM element:

> javascript =  "document.getElementsByTagName('h1').toString()"
> evaluate_javasript("webview", javascript)
[
    [0] "[null]"
]

Samples

This section will cover some common use cases that may be encountered when writing Calabash tests involving web views.

Entering Text

To enter text into HTML input element it is necessary to first touch the DOM element, then use the appropriate Calabash method to enter text (mimicing the steps that a user of the application would perform). Given the following screenshot of an iOS application:

This code snippet is an example of a Cucumber step that would enter text into the previous web view:

When(/^I touch the first name field I should be able to enter the text "([^"]*)" $/) do |new_text|
  p = page(UIWebViewPage).await()
  touch "UIWebView xpath:'//input[contains(@id,\"firstname\")]'"
  wait_for_keyboard
  keyboard_enter_text new_text
end

Scrolling

It is often necessary to scroll a web view to bring DOM elements into view. The general pattern for scroll is to create an expression that will detect when the DOM element is visible, and then call scroll repeatedly until that that expression is satisfied.

In the following screenshots, we see an iOS application that is displaying a web view, and then the webview scrolled until a green horizontal rule appears:

The following code snippet is one example of how do do this in a step using the CSS API:

And(/^I can see the green line with css$/) do
  p = page(UIWebViewPage).await()

  visible = lambda {
    query("UIWebView css:'hr#green_stripe'").count == 1
  }

  counter = 0
  loop do
    break if visible.call || counter == 4
    scroll('UIWebView', :down)
    sleep 0.4
    counter=counter+1
  end
end

Xamarin Workbook

If it's not already installed, install the Xamarin Workbooks app first. The workbook file should download automatically, but if it doesn't, just click to start the workbook download manually.