Autoplay



Transcripted Summary

# What is the WebView Context?

One of the core principles of Appium is that you shouldn't have to change your app to test it.

It is possible to test hybrid applications the same way you can use Selenium for web apps.

There is a bit of technical complexity required so that Appium knows whether you want to automate the native aspect of the app or the web views inside the app.

Once the test is in the web view context, the command set is available in the full WebDriver Selenium API.

In hybrid applications, you have a list of contexts, and you should switch between these contexts if you want it to work with a web view or the native view for the rest of the elements.

So for example, inside your application, you can find something like this 'NATIVE_APP' or 'WEBVIEW_1' app.

This means that your application is hybrid and contains different views, which contains parts for a web browser or web view, and the parts with the native view with your application.

In this demo, we will learn how to automate a hybrid application on Android devices.


import io.appium.java_client.AppiumDriver;
import io.appium.java_client.MobileBy;
import io.appium.java_client.android.AndroidDriver;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.Set;

public class Android_Hybrid_App_Test {

    private static By chromeBtn = MobileBy.AccessibilityId("buttonStartWebviewCD");
    private static By gotoHomeBtn = By.id("goBack");

    private AppiumDriver driver;

    @BeforeTest
    public void setUp() throws MalformedURLException {
        DesiredCapabilities capabilities = new DesiredCapabilities();
        capabilities.setCapability("platformName", "Android");
        capabilities.setCapability("automationName", "UiAutomator1");
        capabilities.setCapability("platformVersion", "8.0");
        capabilities.setCapability("deviceName", "Android Emulator");
        capabilities.setCapability("autoGrantPermissions", true);
        capabilities.setCapability("app", System.getProperty("user.dir")
                + "/apps/selendroid.apk");
        driver = new AndroidDriver(new URL("http://localhost:4723/wd/hub"), capabilities);
    }

    @Test
    public void HybridTest() {
    }

    @AfterTest
    public void tearDown() {
        if (driver != null) {
            driver.quit();
        }
    }
}

# Automating hybrid applications for both Android and iOS

A hybrid application, as we mentioned in our slide, is combined between the native view and the web view - so we have two views inside our application.

To be able to do that, we need to handle the context and the application and then switch between these contexts.

I already prepared my test case for this demo.

This is the Android_Hybrid_App_Test and I already added the application under our apps folder, which is selendroid.apk, and also added this path in the app desired capability.

Also, we have here a new desired capability, which is autoGrantPermissions.

Sometimes, if we are using or trying to run the selendroid application on a new version of Android, for example, 10 or 11, and because this application is old and it's designed for all the versions of Android, maybe we will have one alert that says this application is designed for old applications.

We just need to add this capability to avoid this message.

After that, we can handle the hybrid test inside public void HybridTest().

Let's check our application first.

I prepared the inspection session on my application and here I have an icon for Chrome.



If I click this icon, I have an accessibility id, so I can get this element.

Here, I will find that I don't have anything else in here and I'm still in the android. widget so I am still in the native view.

Then if I click on "Tap" - so click on the button - I open the simulator and then you will find that we have a section for web - so here is a webpage - after I clicked the Chrome icon.



I'm still waiting until a new screenshot is loaded here and then I found that we have a WebView context.

After that, we have a new dropdown displayed here in the Appium inspection session.



If I click on this one, I will find that I have a "NATIVE_APP" - this is the default view - and then I have a "WEBVIEW_io.selendroid.testapp", so I have a web view and I have a native view.

I have two views, which means my application is a hybrid - it contains a native view and a web view.

Inside the web view, the elements come from android.webkit.WebView.

If we find this in our application, this means that our application is a hybrid application.

Under WebView, we will find that we have a text box, and here I have the input name.



So I will find this input name and try to send my name to this element.

But first, I want to switch it from the native view to the web view, then enter the name in the web view, and then switch back to the native view.

Let's continue and return to our script.

Here we need to add two elements.

We need to add the button or the Chrome screen that will give us a view of the web view.

Then we need to click "Back" in Chrome or "Go to home screen" to return from the web view and go back to the default test screen.

So, here I will add two elements.

I will add private static By chromeBtn = MobileBy.AccessibilityID("").

Let's open the inspection session again and click "back" - we need to refresh the screenshot and the source to get the Chrome button.

I need to find this element and the accessibility ID is buttonStartWebviewCD, so I will copy this and pass it.

I also need to import the By from Selenium.

This is the first element and then I need to add one to go back, so we'll add public static By gotoHomeBtn = By.id().

Let's open the inspection session again and click here on Chrome, just to check if there is an accessibility ID or if we already have the ID for this element.

We will click on the "Go to home screen" button and here we have the id - goBack so I will copy this and try to find the element by id. e.

So, here I have added the two elements that I need to work with.


    private static By chromeBtn = MobileBy.AccessibilityId("buttonStartWebviewCD");
    private static By gotoHomeBtn = By.id("goBack");

Then before I start writing my script, I need to create a void function to handle switching between the web view and native view.

So here I will add public void switchToWebView(), and because I have a list of the contexts, I can create a Set - and Set is a String - and then call this contexts and this equals driver.getContextHandles().

This command will get all the contexts inside our application, so I just need to import Set and then I will say for (String context:context) { - so for each context inside contexts, I need to do something.

Then, if (context.contains("WEBVIEW")) - that means that it's already the web view - then I need to switch, so driver.context(context) to switch to the web view, and then I need to add a break.

So, this switches to the web view, and then I need to call it in my test.

But first, let's add our script, so first, we will add a wait with WebDriverWait wait = new WebDriverWait(driver,10).

Then we wait for the presence of the Chrome button and then click when it is located - wait.until(ExpectedConditions.presenceOfElementLocated(chromeBtn)).click().

After I click on the Chrome button, I need to switch to the web view to be able to enter my name in this text box, so I will call switchToWebView().

Then I will add WebElement nameInput = driver.findElement(By.id()), because we already have the input ID - name_input.

Then we will clear nameInput if it has any previous text - nameInput.clear().

Then I can add a String name with, for example, my name "Moataz Nabil".

After I add this value, then we will send key - nameInput.sendKeys(name).

After that, I need to switch back to the native view to be able to click on "Go to home screen" - driver.context("NATIVE_APP").

Then I already have that button, so I will add driver.findElement(gotoHomeBtn).click().


import io.appium.java_client.AppiumDriver;
import io.appium.java_client.MobileBy;
import io.appium.java_client.android.AndroidDriver;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.Set;

public class Android_Hybrid_App_Test {

    private static By chromeBtn = MobileBy.AccessibilityId("buttonStartWebviewCD");
    private static By gotoHomeBtn = By.id("goBack");

    private AppiumDriver driver;

    @BeforeTest
    public void setUp() throws MalformedURLException {
        DesiredCapabilities capabilities = new DesiredCapabilities();
        capabilities.setCapability("platformName", "Android");
        capabilities.setCapability("automationName", "UiAutomator1");
        capabilities.setCapability("platformVersion", "8.0");
        capabilities.setCapability("deviceName", "Android Emulator");
        capabilities.setCapability("autoGrantPermissions", true);
        capabilities.setCapability("app", System.getProperty("user.dir")
                + "/apps/selendroid.apk");
        driver = new AndroidDriver(new URL("http://localhost:4723/wd/hub"), capabilities);
    }

    public void switchToWebView(){
        Set<String> contexts = driver.getContextHandles();
        for (String context: contexts){
            if (context.contains("WEBVIEW")){
                driver.context(context);
                break;
            }
        }
    }

    @Test
    public void HybridTest() {
        WebDriverWait wait = new WebDriverWait(driver,10);
        wait.until(ExpectedConditions.presenceOfElementLocated(chromeBtn)).click();
        switchToWebView();
        WebElement nameInput = driver.findElement(By.id("name_input"));
        nameInput.clear();
        String name = "Moataz Nabil";
        nameInput.sendKeys(name);
        driver.context("NATIVE_APP");
        driver.findElement(gotoHomeBtn).click();
    }

    @AfterTest
    public void tearDown() {
        if (driver != null) {
            driver.quit();
        }
    }
}

So we start by clicking on the button in the native application view, then we wait until the web view is displayed, switch to the web view, then start working with the web elements, switch it back to the native application and then click on the home button.

Let's run our script.

We opened the application, clicked on the button, switched to the web view... now we clear the text, enter the text, switch back to native, and then click on the home button.

So, this is how we handle working with a hybrid application.

We have two views and we need to handle them. We have a native view and we have a web view, and by the way, this is for iOS so also we have hybrid applications and also, in the same way, we can work with the same concepts.



Resources



© 2024 Applitools. All rights reserved. Terms and Conditions Privacy Policy GDPR