Espresso Web

Espresso-Web es un punto de entrada para trabajar con los componentes de la IU de Android WebView. Espresso-Web reutiliza los Atoms de la API WebDriver popular para examinar y controlar el comportamiento de un WebView.

Cuándo usar Espresso-Web

Usa Espresso-Web para probar tus apps híbridas, en especial, la integración de los componentes nativos de la IU de tu app con los componentes de la IU de WebView. Puedes usar la API de Espresso-Web junto con otras API de Espresso para interactuar completamente con elementos web dentro de objetos WebView.

Si necesitas probar solo WebView y no las interacciones entre WebView y los componentes nativos de tu app, procura escribir una prueba web general utilizando un marco como WebDriver. Si usas un marco de trabajo de prueba web, no necesitas usar un dispositivo Android o una máquina virtual Java, lo que hace que tus pruebas se ejecuten de manera más rápida y confiable. Dicho esto, Espresso-Web te permite reutilizar Atoms personalizados de WebDriver, lo que te brinda mucha flexibilidad, especialmente cuando escribes pruebas que planeas ejecutar tanto para app web independientes como para apps que incluyen una IU de Android.

Cómo funciona

De manera similar al método onData() de Espresso, una interacción de WebView incluye varios Atoms. Las interacciones de WebView usan una combinación de lenguaje de programación Java y un puente JavaScript para hacer el trabajo. Dado que no hay ninguna posibilidad de introducir condiciones de carrera exponiendo datos del entorno de JavaScript; todo lo que Espresso ve en el lado basado en Java es una copia aislada que muestra datos de objetos Web.WebInteraction son totalmente compatibles, lo que permite verificar todos los datos que se muestran de una solicitud.

¿Qué es un Atom de WebDriver?

El marco de trabajo de WebDriver usa Atoms para buscar y manipular elementos web de manera programática. WebDriver los utiliza para permitir la manipulación del navegador. Un Atom es conceptualmente similar a ViewAction, una unidad autónoma que realiza una acción en la interfaz del usuario. Expone los Atoms utilizando una lista de métodos definidos, como findElement() y getElement(), para conducir el navegador desde el punto de vista del usuario. Sin embargo, si usas el marco de WebDriver de forma directa, los Atoms deben estar orquestados de manera correcta, lo que requiere una lógica bastante detallada.

En Espresso, las clases Web y Web.WebInteraction unen este código estándar y dan una apariencia de Espresso a la interacción con los objetos WebView. Por lo tanto, en un contexto de WebView, los Atoms se usan como sustitución de los ViewMatchers y ViewActions tradicionales de Espresso.

La API parece bastante simple:

Kotlin

    onWebView()
        .withElement(Atom)
        .perform(Atom)
        .check(WebAssertion)
    

Java

    onWebView()
        .withElement(Atom)
        .perform(Atom)
        .check(WebAssertion);
    

Para obtener más información, consulta la documentación de Selenium sobre Atoms.

Cómo implementar WebView

Sigue la guía que se muestra en las siguientes secciones para trabajar con WebView en las pruebas de la app.

Paquetes

Para incluir Espresso-Web en tu proyecto, completa los siguientes pasos:

  1. Abre el archivo build.gradle de tu app. Por lo general, este no es el archivo build.gradle de nivel superior, sino app/build.gradle.
  2. Agrega la siguiente línea dentro de las dependencias:

        androidTestImplementation 'androidx.test.espresso:espresso-web:3.1.0'
        
  3. Espresso-Web solo es compatible con Espresso 2.2 o versiones posteriores, y con la versión 0.3 o versiones posteriores de la biblioteca de prueba. Por lo tanto, asegúrate de actualizar esas líneas también:

        androidTestImplementation 'androidx.test:runner:1.1.0'
        androidTestImplementation 'androidx.test:rules:1.1.0'
        androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0'
        

Uso de API común

El método onWebView() es el punto de entrada principal cuando se trabaja con WebView en Android usando Espresso. Usa este método para realizar pruebas de Espresso-Web, como las siguientes:

Kotlin

    onWebView()
        .withElement(findElement(Locator.ID, "link_2")) // similar to onView(withId(...))
        .perform(webClick()) // Similar to perform(click())

        // Similar to check(matches(...))
        .check(webMatches(getCurrentUrl(), containsString("navigation_2.html")))
    

Java

    onWebView()
        .withElement(findElement(Locator.ID, "link_2")) // similar to onView(withId(...))
        .perform(webClick()) // Similar to perform(click())

        // Similar to check(matches(...))
        .check(webMatches(getCurrentUrl(), containsString("navigation_2.html")));
    

En este ejemplo, Espresso-Web localiza un elemento DOM cuya ID es "link_2" y hace clic en él. La herramienta luego verifica que WebView envía una solicitud GET que contiene la string "navigation_2.html".

Soporte de JavaScript

Cuando se ejecutan las pruebas, el sistema realiza todas las interacciones de WebView con JavaScript. Por lo tanto, para admitir la evaluación de JavaScript, WebView debe tener habilitado JavaScript.

Para forzar la habilitación de JavaScript, llama a forceJavascriptEnabled() como una acción de la actividad que pruebas, como se muestra en el siguiente fragmento de código.

    @RunWith(AndroidJUnit4::class)
    class MyTestSuite {
        @get:Rule val activityScenarioRule =
            activityScenarioRule<MyWebViewActivity>()

        @Test fun testWebViewInteraction() {
            onWebView().forceJavascriptEnabled()
        }
    }
    

Interacciones web comunes

Las interacciones comunes con objetos Web.WebInteraction incluyen lo siguiente:

  • withElement() hace referencia a un elemento DOM dentro de WebView.

    Ejemplo:

    Kotlin

        onWebView().withElement(findElement(Locator.ID, "teacher"))
        

    Java

        onWebView().withElement(findElement(Locator.ID, "teacher"));
        
  • withContextualElement() hace referencia a un elemento DOM con ámbito dentro de WebView, en relación con otro elemento DOM. Debes llamar a withElement() primero para establecer el objeto de referencia Web.WebInteraction (elemento DOM).

    Ejemplo:

    Kotlin

        .withElement(findElement(Locator.ID, "teacher"))
            .withContextualElement(findElement(Locator.ID, "person_name"))
        

    Java

        .withElement(findElement(Locator.ID, "teacher"))
            .withContextualElement(findElement(Locator.ID, "person_name"));
        
  • check() evalúa una condición, y se asegura que se resolverá como true.

    Ejemplo:

    Kotlin

        onWebView()
            .withElement(findElement(Locator.ID, "teacher"))
            .withContextualElement(findElement(Locator.ID, "person_name"))
            .check(webMatches(getText(), containsString("Socrates")))
        

    Java

        onWebView()
            .withElement(findElement(Locator.ID, "teacher"))
            .withContextualElement(findElement(Locator.ID, "person_name"))
            .check(webMatches(getText(), containsString("Socrates")));
        
  • perform() ejecuta una acción dentro de WebView, como hacer clic en un elemento.

    Ejemplo:

    Kotlin

        onWebView()
            .withElement(findElement(Locator.ID, "teacher"))
            .perform(webClick())
        

    Java

        onWebView()
            .withElement(findElement(Locator.ID, "teacher"))
            .perform(webClick());
        
  • reset() revierte WebView a su estado inicial. Esto es necesario cuando una acción previa, como un clic, introduce un cambio de navegación que hace inaccesibles los objetos ElementReference y WindowReference.

    Nota: Aunque el uso de reset() es útil cuando se hacen afirmaciones en flujos de trabajo de varias páginas, como los envíos de formularios, las pruebas en general deben tener un alcance limitado y centrarse en una sola página.

    Ejemplo:

    Kotlin

        onWebView()
            .withElement(...)
            .perform(...)
            .reset()
        

    Java

        onWebView()
            .withElement(...)
            .perform(...)
            .reset();
        

Ejemplo

En el siguiente ejemplo, se prueba si, después de ingresar texto en WebView y seleccionar un botón Enviar, aparece el mismo texto dentro de un elemento diferente en el mismo WebView:

Kotlin

    const val MACCHIATO = "Macchiato"

    @RunWith(AndroidJUnit4::class)
    class MyEspressoWebTestSuite {

        @Test fun typeTextInInput_clickButton_SubmitsForm() {
            // Create an intent that displays a web form.
            val webFormIntent = Intent()
            // ...

            // Lazily launch the Activity with a custom start Intent per test.
            ActivityScenario.launchActivity(webFormIntent)

            // Selects the WebView in your layout. If you have multiple WebView
            // objects, you can also use a matcher to select a given WebView,
            // onWebView(withId(R.id.web_view)).
            onWebView()
                // Find the input element by ID.
                .withElement(findElement(Locator.ID, "text_input"))

                // Clear previous input and enter new text into the input element.
                .perform(clearElement())
                .perform(DriverAtoms.webKeys(MACCHIATO))

                // Find the "Submit" button and simulate a click using JavaScript.
                .withElement(findElement(Locator.ID, "submitBtn"))
                .perform(webClick())

                // Find the response element by ID, and verify that it contains the
                // entered text.
                .withElement(findElement(Locator.ID, "response"))
                .check(webMatches(getText(), containsString(MACCHIATO)))
        }
    }
    

Java

    public static final String MACCHIATO = "Macchiato";

    @Test
    public void typeTextInInput_clickButton_SubmitsForm() {
        // Create an intent that displays a web form.
        Intent webFormIntent = new Intent();
        // ...

        // Lazily launch the Activity with a custom start Intent per test.
        ActivityScenario.launchActivity(webFormIntent);

        // Selects the WebView in your layout. If you have multiple WebView objects,
        // you can also use a matcher to select a given WebView,
        // onWebView(withId(R.id.web_view)).
        onWebView()
            // Find the input element by ID.
            .withElement(findElement(Locator.ID, "text_input"))

            // Clear previous input and enter new text into the input element.
            .perform(clearElement())
            .perform(DriverAtoms.webKeys(MACCHIATO))

            // Find the "Submit" button and simulate a click using JavaScript.
            .withElement(findElement(Locator.ID, "submitBtn"))
            .perform(webClick())

            // Find the response element by ID, and verify that it contains the
            // entered text.
            .withElement(findElement(Locator.ID, "response"))
            .check(webMatches(getText(), containsString(MACCHIATO)));
    }
    

Recursos adicionales

Para obtener más información sobre el uso de Espresso-Web en pruebas de Android, consulta los siguientes recursos.

Ejemplos

  • WebBasicSample: Usa Espresso-Web para interactuar con objetos WebView.